Programming: Minimum steps required to convert a binary number to zero - java

I was working on a programming exercise and was stuck on figuring out the correct algorithm. Here is the problem:
Given a decimal number, how many minimum possible steps are required to convert this to zero provided:
Change the bit i if the next bit i+1 is '1' and all the other bits i+2 and later are 0
Change the last bit without restriction
For example:
if input is (8)Base10 = (1000)Base2, then the steps taken are:
1000→1001→1011→1010→1110→1111→1101→1100→0100→0101→0111→0110→0010→0011→0001→0000
total 15 steps are required.
Complete the following definition:
int minStepsRequired(long number)
It's ok to get a pseudo code or just the algorithm. This is not a homework or assignment.

This is a wonderful problem for a recursive algorithm.
If the length of the binary representation is 0, you can already tell the answer. Or if length 0 is not allowed, then if the length is 1 you tell the answer depending on whether that one bit is 0 or 1.
If the length is longer than 1:
If the first bit is 0, the answer is the same as it would be without that 0 bit. Remove it and call recursively to get the answer.
If the first bit is 1, divide into three subproblems and find the step count for each:
Establish a situation where you are allowed to change the leading 1 to 0. This means it should be followed by a 1 and then all 0s. Write a recursive auxiliary algorithm for this. It is going to be quite similar to the main algorithm, and likely they can share some logic.
Flip the 1 to 0 (1 step)
Convert the remaining bits bits to 0. Another recursive call.
The algorithm may take a long time. It is actually counting the steps, so takes time proportional to the number of steps, which I think is roughly proportional to the input number. Your method takes a long argument, but with my algorithm for large long values it may not terminate witin the lifetime of the computer it is running on. Also the number of steps may overflow an int and even a long (if the input is a negative long value).
The fast way
The following solution doesn’t require recursion and runs in constant time. I can’t explain properly how it works, which is a serious problem if we want to use it for something. I played with some examples, saw a pattern and generalized it. By contrast IMHO some of the beauty of the recursive solution above is that it is straightforward to understand (if you understand recursion).
Example: Input 8 or 1000 binary. Result 15 or 1111 binary. The pattern is: each bit of the result is the XOR of the previous bit of the result and the bit in the same position in the input. So from 1000 just copy the front bit, 1. The following bit is 1 XOR 0 = 1, where 1 is the front bit of the result and 0 is taken from the input. The remaining two bits are calculated the same way.
A longer example so you can check if you understood:
Input: 115 = 1110011
Result: 1011101 = 93
Or in code:
static BigInteger calculateStepsRequired(long number) {
// Take sign bit
int bit = number < 0 ? 1 : 0;
BigInteger result = BigInteger.valueOf(bit);
for (int i = 0; i < 63; i++) {
number = number << 1;
int sign = number < 0 ? 1 : 0;
bit = (bit + sign) % 2;
result = result.shiftLeft(1).add(BigInteger.valueOf(bit));
}
return result;
}
I have checked this method against my own implementation of the first algorithm above using various inputs up to 100 000 000, and they always agree, so I believe that the fast method is correct too. I still suggest that you should code, run and test it to verify that I got it right.

At first, I tried to solve it with a recursive depth-first function (in NodeJS) but it just worked for small numbers - an input value such as 10^5 would generate a runtime error due to the number of recursive calls in the stack.
So then I tried to see how I could reduce the problem to the sum of smaller problems and found out that the number of steps for N, being N a power of 2, was
Rule #1
N * 2 - 1
(e.g.: number of steps for 2 is 3, for 32 is 63, for 256 is 511, and so on).
Then I had find what to do with any other number (that is not a power of 2) and since any integer is the sum of different powers of 2 (hence the binary representation), I only had to see if the number of steps would add up as well ... but it was not the case. However, I did find that I had to not just add the number of steps from every power of two, but to
Rule #2
subtract and add the steps in an alternate fashion, starting from the highest order digit
Demonstration
Given number 42 (101010 in binary)
Let's first apply Rule #1
1 0 1 0 1 0
^ ^ ^ ^ ^ ^
| | | | | |_ 0 steps
| | | | |___ 2*2-1 = 3 steps
| | | |_____ 0 steps
| | |_______ 2*8-1 = 15 steps
| |_________ 0 steps
|___________ 2*32-1 = 63 steps
And secondly, applying Rule #2:
63 - 15 + 3 = 51
The total number of steps is 51
Implementation (JavaScript)
function minOperations(n) {
const bin = n.toString(2);
const digitCount = bin.length;
let accumulator = 0;
let sign = 1;
for (let i = 0; i < digitCount; ++i) {
const digit = Number.parseInt(bin.charAt(i));
const power = digit > 0 ? Math.pow(2, digitCount - (i + 1)) : 0;
const steps = digit * (power * 2 - 1);
accumulator += steps * sign;
sign = sign * (digit == 0 ? 1 : -1);
}
return accumulator;
}

Here is a recursive PHP function for computing the number of steps required. It operates by noting there are two possible requirements:
convert a string to 0s (the overall requirement); and
convert a string to a 1 followed by a string of 0s (to allow flipping the preceding digit)
The second requirement is obviously an extension of the first, and so it's possible to write a recursive function which does both. It has a special case for the single digit length string, just checking if it needs to be flipped or not.
function reduce($bits, $value = '0') {
if (strlen($bits) == 1) {
// a single bit can be flipped as needed
return ($bits[0] == $value) ? 0 : 1;
}
if ($bits[0] == $value) {
// nothing to do with this bit, flip the remainder
return reduce(substr($bits, 1));
}
// need to convert balance of string to 1 followed by 0's
// then we can flip this bit, and then reduce the new string to 0
return reduce(substr($bits, 1), '1') + 1 + reduce(str_pad('1', strlen($bits) - 1, '0'));
}
Demo on 3v4l.org
This function can be adapted to store the actual steps taken, then the number of steps is just the count of that array (-1, since we put the original value in the array too). To store the steps we need to keep track of the first part of the string ($prefix in the below code) as well as the part we are reducing:
function reduce($bits, $prefix, $value = '0') {
if (strlen($bits) == 1) {
// a single bit can be flipped as needed
return array($prefix . ($bits[0] == '0' ? '1' : '0'));
}
if ($bits[0] == $value) {
// nothing to do with this bit, flip the remainder
$prefix .= $bits[0];
return reduce(substr($bits, 1), $prefix);
}
// need to convert balance of string to 1 followed by 0's
$prefix .= $bits[0];
$steps = reduce(substr($bits, 1), $prefix, '1');
// now we can flip this bit
$prefix = substr($prefix, 0, -1) . ($bits[0] == '0' ? '1' : '0');
$steps[] = $prefix . str_pad('1', strlen($bits) - 1, '0');
// now reduce the new string to 0
$steps = array_merge($steps, reduce(str_pad('1', strlen($bits) - 1, '0'), $prefix));
return $steps;
}
You can run this like so:
$bin = decbin($i);
$steps = array_merge(array($bin), reduce($bin, ''));
echo "$i ($bin) takes " . (count($steps) - 1) . " steps\n";
print_r($steps);
Output for an input of 8:
8 (1000) takes 15 steps
Array
(
[0] => 1000
[1] => 1001
[2] => 1011
[3] => 1010
[4] => 1110
[5] => 1111
[6] => 1101
[7] => 1100
[8] => 0100
[9] => 0101
[10] => 0111
[11] => 0110
[12] => 0010
[13] => 0011
[14] => 0001
[15] => 0000
)
Demo on 3v4l.org
Gray code
Looking at the steps we can see that this is actually a Gray code (Reflected Binary Code) counting from the original value down to 0. So if we generate a list of sufficient codes to cover the starting value, we can simply look for the binary representation of the starting value in that list, and that will give us the number of steps required to get back to 0:
function gray_code($bits) {
if ($bits == 1) {
return array('0', '1');
}
else {
$codes = gray_code($bits - 1);
return array_merge(array_map(function ($v) { return '0' . $v; }, $codes),
array_map(function ($v) { return '1' . $v; }, array_reverse($codes))
);
}
}
$value = 8;
$bin = decbin($value);
// get sufficient gray codes to cover the input
$gray_codes = gray_code(strlen($bin));
$codes = array_flip($gray_codes);
echo "$bin takes {$codes[$bin]} steps to reduce to 0\n";
// echo the steps
for ($i = $codes[$bin]; $i >= 0; $i--) {
echo $gray_codes[$i] . PHP_EOL;
}
Demo on 3v4l.org
If you don't need the individual steps you can just use a Gray code to binary converter to find the number of steps. This is super fast:
function gray_to_binary($value) {
$dec = $value;
for ($i = 1; $i < strlen($value); $i++) {
$dec[$i] = (int)$dec[$i-1] ^ (int)$value[$i];
}
return $dec;
}
echo bindec(gray_to_binary(decbin(115)));
Output:
93
Demo on 3v4l.org
A Gray Code Generator
We can use an iterative Gray code generator to count down the steps from our original code. The advantage of this is that it doesn't consume any memory to store the codes so it can work for very large numbers. This version uses a Gray code to binary converter that works with integers rather than strings as did the one above:
function gray_to_binary($value) {
$dec = 0;
$bits = floor(log($value, 2));
for ($i = $bits; $i >= 0; $i--) {
$dec = $dec | (((($dec >> ($i + 1)) ^ ($value >> $i)) & 1) << $i);
}
return $dec;
}
function iterate_gray($value) {
// get the equivalent starting binary value
$code = decbin($value);
yield $code;
$len = strlen($code);
$count = gray_to_binary($value);
while ($count > 0) {
// flip the bit which corresponds to the least significant 1 bit in $count
$xor = 1;
while (($count & $xor) == 0) $xor <<= 1;
$value ^= $xor;
yield sprintf("%0{$len}b", $value);
$count--;
}
}
foreach (iterate_gray(8) as $code) {
echo $code . PHP_EOL;
}
Output:
1000
1001
1011
1010
1110
1111
1101
1100
0100
0101
0111
0110
0010
0011
0001
0000
Demo on 3v4l.org

Here is a PHP implementation of Ole's "fast way" algorithm. The idea is the same:
Initialize the result with the first bit of the number (starting from the left)
For every following bit of the number, XOR it with the previous bit of the result, which gives a new bit for the result
function getBit($number, $i)
{
// Extracts bit i from number
return ($number & (1<<$i)) == 0 ? 0 : 1;
}
function minStepsRequired($number)
{
$i = 30; // Enough to handle all positive 32-bit integers
$bit = getBit($number, $i); // First bit
$res = $bit;
do
{
$i--;
$bit ^= getBit($number, $i); // Computes XOR between previous bit of the result and current bit of the number
$res = ($res<<1) + $bit; // Shifts the result to the left by 1 position and adds the new bit
}
while($i>0);
return $res;
}
var_dump(minStepsRequired(8)); // Outputs 15
var_dump(minStepsRequired(115)); // Outputs 93

It is important to notice that the first k bits, which are zeroes can be left as they are and you only start with the (k + 1)'th bit and we ignore all the starting bits, having a value of zero and always aim to increase their number. This is our primary goal and thus, we always reduce the problem-space to a similar, but smaller problem-space. Now, assuming that your number looks like
1b1b2b3...bn
you need to make sure that b1 is 1 and b2, b3, ..., bn is 0 in order to be able to modify the bit prior to b1 to 0. After that happened, you know that b2 is 1 and all the subsequent bits are 0, then the new goal is to change b2 to 0, knowing that all the subsequent bits are 0.
You can keep track of your progress with a stack which can have as much elements as many bits you are working with, always its top will represent your current goal.
So, when you want to zero your first bit, then achieving the right sequence of subsequent bits represent subtasks for you before you can change your bit and once you succeeded doing so, you need to proceed similarly, but ignoring the first bit. You can number the steps.
Assuming that a number of
1...0000000
can be zeroed in 2^n - 1 steps, the total number of steps to do equals with 2^n - 1 + the number of steps needed to achieve the combination we see above. I didn't check whether it's 2^n - 1 though

private static int reduce(String s) {
int count = 0;
char[] ch = s.toCharArray();
for (int i = ch.length - 1; i >= 0; i--) {
if (i == 0 && ch[i] == '0') {
return count - 1;
}
if (i == 0 && ch[i] == '1') {
return count + 1;
}
if (ch[i] == '0') {
count++;
} else {
count++;
ch[i] = '0';
i++;
}
}
return count;
}

def minOperations(n):
number = []
while n>0:
number.append(n%2)
n = n // 2
ans = 0
sign = 1
for i in range(len(number)):
if number[i] == 1:
ans = (2**(i+1) - 1) - ans
return ans

Related

how to convert negative number to binary in java?

I'm trying to convert a negative long number (e.g. -1065576264718330231L) to binary.
First, I convert negative number to positive one by removing the sign;
Second, I get the binary of the result from first step;
then I get stuck with "add one" to the binary result of the second step,that is :
please! how to implement the third step?
or do you have other better solutions?!
http://geekexplains.blogspot.com/2009/05/binary-rep-of-negative-numbers-in-java.html
Signed integers/longs use the two-complements notation:
Say you have -6:
6 = 000..000 110 binary
111..111 001 one's complement
111..111 010 add 1
-6 = 111..111 010
The advantage is that normal binary addition works (-6+6=0), there is just one 0.
Of you could simply subtract 6 from 0:
000
110
------ -
0
1 borrow 1 (all ones at the top)
0
...111
111...111010 = -6
Note:
If one borrows (subtracts one of) 0000000, one actually uses an overflow:
(1)0000000 which minus 1 delivers
1111111
Goodies:
long n = -1065576264718330231L;
System.out.println(Long.toUnsignedString(n, 2));
System.out.println(Long.toString(n, 2));
Given the long value is -1065576264718330231L.
long v = -1065576264718330231L;
System.out.println(Long.toBinaryString(v));
Or you can code the algorithm yourself
StringBuilder sb = new StringBuilder();
while (v != 0) {
sb.append(v < 0 ? '1'
: '0');
v <<= 1;
}
System.out.println(sb.toString());
If you want to convert a positive number to negative using 2's complement you can do the following:
long pos = 23;
long neg = ~pos + 1;
System.out.println(pos);
System.out.println(neg);
But all Strings, ints, longs, etc. are inherently stored in binary and are displayed in different formats based on context.

Undoing bitwise operations

I have a Java function written by another programmer, which uses bitwise manipulation. I need a function that will undo the process (if possible). Perhaps some of you are more savvy than I with these operators. Here's what needs to be undone:
public void someFunc(int[] msg, int[] newMsg) {
int i = SOME_LENGTH_CONSTANT;
for (int j = 0; j < newMsg.length; j++) {
// msg[i] Shift left by 8 bits bitwise or with next msg[i+1]
// then bitwise not (~) and bitwise and with $FFF
newMsg[j] = (~(((msg[i] & 0x0f) << 8) | (msg[i + 1]))) & 0xfff;
i += 2;
}
}
I just wanted to try to do it, here is the results of my attempt.
In the beginning I split the expression into single operations:
int t1 = msg[i] & 0x0f;
Here is we lose all except for the last 4 bits.
int t2 = t1 << 8;
Clear low 8 bits by shifting t1.
int t3 = t2 | msg[i + 1];
Here we should understand if m[i + 1] is large than 255 (particularly m[i + 1] & 0xf00 > 0), we are not able to restore the low 4 bits of m[i] because they are irreversibly overwritten.
int t4 = ~t3;
Just a negation.
newMsg[j] = t4 & 0xfff;
Take low 12 bits.
Just did these steps in reverse order:
public static void someFuncRev(int[] msg, int[] newMsg) {
for (int i = 0; i < msg.length; ++i) {
newMsg[2 * i] = (~msg[i] >> 8) & 0xf; // take 11-8 bits
newMsg[2 * i + 1] = ~msg[i] & 0xff; // take 7-0 bits
}
}
I assumed SOME_LENGTH_CONSTANT == 0. It is easy to adjust the constant.
So, when the values inside msg are <=15, the function above recovers the initial sequence.
In case when the values are >15 and <=255, for msg[i] we can restore only 4 bits, msg[i + 1] are restored completely.
If the values are >255, we can't restore msg[i] because it was correpted by bits of msg[i + 1] (look above at the point no. 3); can restore 8 bits of msg[i + 1].
I hope this helps you.
My version, behold:
public void undoFunc(int[] newMsg, int[] original) {
int i = SOME_LENGTH_CONSTANT; // starting point
for (int j = 0; j < newMsg.length; j++) { // Iterate over newMsg
original[i] = ~((newMsg[j]&0xff00)>>8)&0x000f; // &0x000f to get rid of "mistakes" when NOT-ing
original[i+1] = (~(newMsg[j]&0x00ff)) & 0xff;
// i = initial value + 2 * j
i+=2;
}
}
What does your code do?
The input is an integer array. Every two values are used to create one value in the 'output' (newMsg) array.
First, it removes the left four bits of the first value in the input.
Then it "scrolls" that value 8 places to the left and puts zeroes in the empty spots.
It places the second value, msg[i+1], in the zeroes in the four rightmost bits.
It negates the value, all ones become zeroes and all zeroes become ones.
When 4) was done, the 4 leftmost bits (cleared in step 1)) become ones, so it undoes this with a &0x0FFF.
Example iteration:
msg[i] == 1010'1011
msg[i+1] == 0010'0100
1) 1010'1011 -> 0000'1011
2) 0000'1011 -> 0000'1011'0000'0000
3) 0000'1011'0000'0000 -> 0000'1011'0010'0100
4) 0000'1011'0010'0100 -> 1111'0100'1101'1011
5) 1111'0100'1101'1011 -> 0000'0100'1101'1011
newMsg[j] == 0000'0100'1101'1011 == 0x04DB (I think, from memory)
What my code does:
Getting the value of (what used to be) msg[i+1] is easy, it's the opposite/NOT of the rightmost 8 bits. Because negating it turns all leading zeroes into ones, I'll AND it with 0xff.
Getting the value of (what used to be) msg[i] was more difficult. First scrolled the leftmost 8 bits to the right. Then I negate the value. But the four unused/lost bits are now ones, and I expect that the OP wants these to be zeroes, so I &0x000f it.
NOTE: I used hexes with leading zeroes to make it more clear. These are not necessary.
NOTE: I divided the binary numbers into four bits for readability. So 0000'0100'1101'1011 is actually (0b)0000010011011011.
The values of msg[i+1] are recovered, but the leftmost four bits of msg[i] are lost.
Fwew.
Original Post:
In your code, you use &. What & does, is turn all 'agreeing bits' (when a bit from byte a and the equally significant bit from byte b are both 1) into 1s and the rest into 0s. This means that all bits that don't agree are, as #Mike Harris said, gone and destroyed.
Example & (and operation):
1010 & 0110 =
1 & 0 => 0
0 & 1 => 0
1 & 1 => 1
0 & 0 => 0
= 0010
As you see, only the second and third most significant bits (or zero-inclusive first and second least significant bit) of byte a are kept (bit #4/#0 is 'luck'), because they are 1s in byte b.
You can reverse all bits that are 1s in byte b in your code (one of which is fff, or 1111 1111 1111 in binary, though remember all bits more significant than the first one are removed, because 1111 1111 1111 == 000000000...00111111111111). But this won't reverse it, and only works depending on what the purpose of reversing it is.
More about the AND Bitwise operation on Wikipedia.

What is my code for inverting all the bits in a 32 bit integer producing the incorrect output?

This is from a hacker rank practice problem(not a competition) https://www.hackerrank.com/challenges/flipping-bits. Just doing this for practice.
The problem just asks you to take a set number for 32 bit integers and for each one, invert all the bits inside that integer and print out the result
Here's my code so far
static long getComplement(long c) {
long complement = 0;
for(int k = 31; k >= 0 ; k --) {
long evaluateBit = c >> k;
if(evaluateBit == 1) {
evaluateBit = 0;
} else {
evaluateBit = 1;
}
complement += evaluateBit << k;
}
return complement;
}
Here is my high level pseudo code thinking. I will evaluate every bit in the integer. To do this, I have to right shift the bit by its position(something that was at position 31 would have to be right shifted by 31 to get to position 0 so I can evaluate it). That's why my loop started at 31 and ends at 0. And then once i get the bit at that position, I will invert it with a conditional statement and then left shift the result by the same result. I will finally add it to the sum I am keeping (what was 0 * 2 ^ 31 will consist of 1 * 2 ^ 31)
Does anyone see any problems with my pseudo code?
There has to be a problem because when I tried running the code in my IDE, here is what I got when I debugged the code
I tried doing a test run with a input of 0.
After my first run(k=31), I somehow get a negative number. Does anyone know what the problem is or how I can fix this?
I made sure that I used the right shift operators as well, from How do shift operators work in Java?
Your first iteration changes the left most bit from 0 to 1. This is the sign bit, so of course you got a negative number.
EDIT :
change
evaluateBit = (c >> k);
to
evaluateBit = (c >> k) & 1;
In order for evaluateBit to really contain the value of a single bit.

new to java - trying to understand: checker |= (1 << val)

the following code will check to see if you have any duplicate characters in the string, but i don't understand the if clause:
public static boolean isUniqueChars(String str) {
int checker = 0;
for (int i = 0; i < str.length(); ++i) {
int val = str.charAt(i) - 'a';
if ((checker & (1 << val)) > 0)
return false;
checker |= (1 << val);
}
return true;
}
I tried to look up some references, I am new to bit shifting, all i understand is that << shifts the binary number left or right. Can you explain to me how checker |= (1 << val) works ? and that 'if' statement as well.
I was also going through this book Cracking the Code Interview and ended up googling for a clear explanations. Finally I understood the concept.
Here is the approach.
Note :
We will assume, in the below code, that the string is only lower case ‘a’ through ‘z’. This will allow us to use just a single int.
Java integer is of size 32
Number of lower case alphabets is 26
So we can clearly set 0/1 (true or false) value inside one integer in
decimal notation.
It is similar to bool visited[32] .
bool uses 1 byte. Hence you need 32 bytes for storing bool visited[32].
Bit masking is a space optimization to this.
Lets start :
You are looping through all the characters in the string.
Suppose on i'th iteration you found character 'b' .
You calculate its 0 based index.
int val = str.charAt(i) - 'a';
For 'b' it is 1. ie 98-97 .
Now using left shift operator, we find the value of 2^1 => 2.
(1 << val) // 1<<1 => 10(binary)
Now let us see how bitwise & works
0 & 0 -> 0
0 & 1 -> 0
1 & 0 -> 0
1 & 1 -> 1
So by the below code :
(checker & (1 << val))
We check if the checker[val] == 0 .
Suppose we had already encountered 'b'.
check = 0000 0000 0000 0000 0000 1000 1000 0010 &
'b' = 0000 0000 0000 0000 0000 0000 0000 0010
----------------------------------------------
result= 0000 0000 0000 0000 0000 0000 0000 0010
ie decimal value = 2 which is >0
So you finally we understood this part.
if ((checker & (1 << val)) > 0)
return false;
Now if 'b' was not encountered, then we set the second bit of checker using bitwise OR.
( This part is called as bit masking. )
OR's Truth table
0 | 0 -> 0
0 | 1 -> 1
1 | 0 -> 1
1 | 1 -> 1
So
check = 0000 0000 0000 0000 0000 1000 1000 0000 |
'b' = 0000 0000 0000 0000 0000 0000 0000 0010
----------------------------------------------
result= 0000 0000 0000 0000 0000 1000 1000 0010
So that simplifies this part:
checker |= (1 << val); // checker = checker | (1 << val);
I hope this helped someone !
Seems like I am late to the party, but let me take a stab at the explanation.
First of all the AND i.e & operation:
0 & 0 = 0
1 & 0 = 0
0 & 1 = 0
1 & 1 = 1
So basically, if you are given a bit, and you want to find out if its 1 or 0, you just & it with a 1. If the result is 1 then you had a 1, else you had 0. We will use this property of the & below.
The OR i.e | operation
0 | 0 = 0
1 | 0 = 1
0 | 1 = 1
1 | 1 = 1
So basically, if you are given a bit, and you want to do something to it so that the output is always 1, then you do an | 1 with it.
Now, In Java the type int is 4 bytes i.e. 32 bits. Thus we can use an int itself as a data-structure to store 32 states or booleans in simpler terms, since a bit can either be 0 or 1 i.e false or true. Since we assume that our string is composed of only lower case characters, we have enough space inside our int to store a boolean for each of the 26 chars!
So first we initialize our data-structure that we call checker to 0 which is nothing but 32 zeros: 0000000000000000000000.
So far so good?
Now we go through our string, for each character, first we get an integer representation of the character.
int val = str.charAt(i) - 'a';
We subtract a from it because we want our integer to be 0 based. So if vals:
a = 0 i.e. `0000000000000000000000`
b = 1 i.e. `0000000000000000000001`
c = 2 i.e. `0000000000000000000010`
d = 4 i.e. `0000000000000000000100`
Now as seen above, a is 32 zeros, but rest of the characters have a single 1 and 31 zeros. So when we use these characters, we left shift each of them by 1, i.e. (1 << val), so each of them have a single 1 bit, and 31 zero bits:
a = 1 i.e. `0000000000000000000001`
b = 2 i.e. `0000000000000000000010`
c = 4 i.e. `0000000000000000000100`
d = 8 i.e. `0000000000000000001000`
We are done with the setup. Now we do 2 things:
First assume all characters are different. For every char we encounter, we want our datastructure i.e. checker to have 1 for that char. So we use our OR property descrived above to generate a 1 in our datastructure, and hence we do:
checker = checker | (1 << val);
Thus checker stores 1 for every character we encounter.
Now we come to the part where characters can repeate. So before we do step 1, we want to make sure that the checker already does not have a 1 at the position corresponding to the current character. So we check the value of
checker & (1 << val)
So with help of the AND property described above, if we get a 1 from this operation, then checker already had a 1 at that position, which means we must have encountered this character before. So we immediately return false.
That's it. If all our & checks return 0, we finally return true, meaning there were no character repititions.
1 << val is the same as 2 to the degree of val. So it's a number which has
just one one in its binary representation (the one is at position val+1, if you count from
the right side of the number to the left one).
a |= b means basically this: set in a all binary flags/ones from the
binary representation of b (and keep those in a which were already set).
The other answers explain the coding operator usages but i don't think they touch the logic behind this code.
Basically the code 1 << val is shifting 1 in a binary number to a unique place for each character for example
a-0001
b-0010
c-0100
d-1000
As you can notice for different characters the place of 1 is different
checker = checker | (1 << val)
checker here is Oring (basically storing 1 at the same place as it was in 1<<val)
So checker knows what characters have already ocurred
Let's say after the occurence of a,b,c,d checker would look like this
0000 1111
finally
if ((checker & (1 << val)) > 0)
checks if that character has already been occured before if yes return false.To explain you should know a little about AND(&) operation.
1&1->1
0&0->0
1&0->0
So checker currently have 1 in places whose corresponding characters have already occured the only way the expression inside if statement is true
if a character occurs twice which leads 1&1->1 > 0
This sets the 'val'th bit from the right to 1.
1 << val is a 1 shifted left val times. The rest of the value is 0.
The line is equivalent to checker = checker | (1 << val). Or-ing with a 0 bit does nothing, since x | 0 == x. But or-ing with 1 always results in 1. So this turns (only) that bit on.
The if statement is similar, in that it is checking to see if the bit is already on. The mask value 1 << val is all 0s except for a single 1. And-ing with 0 always produces 0, so most bits in the result are 0. x & 1 == x, so this will be non-zero only if that bit at val is not 0.
checker |= (1 << val) is the same as checker = checker | (1 << val).
<< is left bit shift as you said. 1 << val means it's a 1 shifted val digits left.
Example: 1 << 4 is 1000. A left bit shift is the same as multiply by 2. 4 left bit shifts are 4 times 1 multiplied by 2.
1 * 2 = 2 (1)
2 * 2 = 4 (2)
4 * 2 = 8 (3)
8 * 2 = 16 = (4)
| operator is bitwise or. It's like normal or for one bit. If we have more than one bit you do the or operation for every bit.
Example:
110 | 011 = 111
You can use that for setting flags (make a bit 1).
The if condition is similar to that, but has the & operator, which is bitwise and. It is mainly used to mask a binary number.
Example:
110 | 100 = 100
So your code just checks if the bit at place val is 1, then return false, otherwise set the bit at place val to 1.
It means do a binary OR on the values checker and (1 << val) (which is 1, left shifted val times) and save the newly created value in checker.
Left Shift (<<)
Shift all the binary digits left one space. Effectively raise the number to 2 to the power of val or multiply the number by 2 val times.
Bitwise OR (|)
In each binary character of both left and right values, if there is a 1 in the place of either of the two numbers then keep it.
Augmented Assignment (|=)
Do the operation (in this case bitwise OR) and assign the value to the left hand variable. This works with many operators such as:-
a += b, add a to b and save the new value in a.
a *= b, multiply a by b and save the new value in a.
Bitwise shift works as follows:
Example: a=15 (bit representation : 0000 1111)
For operation: a<<2
It will rotate bit representation by 2 positions in left direction.
So a<<2 is 0011 1100 = 0*2^7+0*2^6+1*2^5+1*2^4+1*2^3+1*2^2+0*2^1+0*2^0 = 1*2^5+1*2^4+1*2^3+1*2^2 = 32+18+8+4=60
hence a<<2 = 60
Now:
checker & (1<<val),
will always be greater then 0, if 1 is already present at 1<<val position.
Hence we can return false.
Else we will assign checker value of 1 at 1
I've been working on the algorithm and here's what I noticed that would also work. It makes the algorithm easier to understand when you exercise it by hand:
public static boolean isUniqueChars(String str) {
if (str.length() > 26) { // Only 26 characters
return false;
}
int checker = 0;
for (int i = 0; i < str.length(); i++) {
int val = str.charAt(i) - 'a';
int newValue = Math.pow(2, val) // int newValue = 1 << val
if ((checker & newValue) > 0) return false;
checker += newValue // checker |= newValue
}
return true;
When we get the value of val (0-25), we could either shift 1 to the right by the value of val, or we could use the power of 2s.
Also, for as long as the ((checker & newValue) > 0) is false, the new checker value is generated when we sum up the old checker value and the newValue.
public static boolean isUniqueChars(String str) {
int checker = 0;
for (int i = 0; i < str.length(); ++i) {
int val = str.charAt(i) - 'a';
if ((checker & (1 << val)) > 0)
return false;
checker |= (1 << val);
}
return true;
}
1 << val uses right shift operator. Let us say we have character z. ASCII code of z is 122. a-z is 97- 122 = 25. If we multiply 1*(2)^25 = 33554432. Binary of that is 10000000000000000000000000
if checker has 1 on its 26th bit then this statement if ((checker & (1 << val)) > 0) would be true and isUniqueChar would return false.
otherwise checker would turn it's 26th bit on. |= operator(bitwise or and assignment operator) does checker bitwise OR 10000000000000000000000000. Assigns the result to checker.

Single Number II from leetcode

The question about Single Number II from leetcode is:
Given an array of integers, every element appears three times except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
Actually, I already found the solution from website, the solution is:
public int singleNumber(int[] A) {
int one = 0, two = 0;
for (int i = 0; i < A.length; i++) {
int one_ = (one ^ A[i]) & ~two;
int two_ = A[i] & one | ~A[i] & two;
one = one_;
two = two_;
}
return one;
}
However, I do not know why this code can work and actually I do not know the way of thinking of this problem when I first saw it? Any help. thx!
So, I was going through some coding problems and stuck with this one for quite some time, and after a ton of research on google, going through different posts and portals, I have understood this problem. Will try to explain it as simple as I can.
The problem has 3 solutions:
Using HashMap: But as we know that will add O(N) space complexity and we don't want that. But for a little bit of understanding, the approach is to iterate the array, get the count of the digits and maintain it in map. Then iterate the map and where the count is 1 that will be your answer.
Using Bitwise operators: The logic for this approach is to think the numbers in bits and then add all the bits of each position. So after adding you will see that the sum is either multiple of 3 or multiple of 3 + 1 (Because the other number is occurring once only). After this, if you do a modulo on this sum you will have the result. You will understand better with the example.
Example: Array - [5, 5, 5, 6]
 5 represented in bits: 101
 6 represented in bits: 110
 [ 101, 101, 101, 110] (Binary Reprenstation of values) After adding to particular positions, we will have
  0th -> 3, 1th -> 1,  2nd -> 4
 and if you mod by 3 it will become
  0th -> 0,  1th -> 1, 2nd -> 1
 which in decimal representation is our answer 6.
Now we need to code the same. I have explained the code using comments.
public class SingleNumberII {
/*
* Because the max integer value will go upto 32 bits
* */
private static final int INT_SIZE = 32;
public int singleNumber(final int[] A) {
int result = 0;
for(int bitIterator = 0; bitIterator < INT_SIZE; bitIterator++) {
int sum = 0, mask = (1 << bitIterator);
/*
* Mask:
* 1 << any number means -> it will add that number of 0 in right of 1
* 1 << 2 -> 100
* Why we need mask? So when we do addition we will only count 1's,
* this mask will help us do that
* */
for(int arrIterator = 0; arrIterator < A.length; arrIterator++) {
/*
* The next line is to do the sum.
* So 1 & 1 -> 0
* 1 & 0 -> 0
* The if statement will add only when there is 1 present at the position
* */
if((A[arrIterator] & mask) != 0) {
sum++;
}
}
/*
* So if there were 3 1's and 1 0's
* the result will become 0
* */
if(sum % 3 == 1) {
result |= mask;
}
}
/*So if we dry run our code with the above example
* bitIterator = 0; result = 0; mask = 1;
* after for loop the sum at position 0 will became 3. The if
* condition will be true for 5 as - (101 & 001 -> 001) and false for 6
* (110 & 001 -> 000)
* result -> 0 | 1 -> 0
*
* bitIterator = 1; result = 0; mask = 10;
* after for loop the sum at position 1 will became 1. The if
* condition will be true for 6 as - (110 & 010 -> 010) and false for 5
* (101 & 010 -> 000)
* result -> 00 | 10 -> 10
*
* bitIterator = 2; result = 10; mask = 100;
* after for loop the sum at position 2 will became 4. The if
* condition will be true for 6 as - (110 & 100 -> 100) and true for 5
* (101 & 100 -> 100)
* result -> 10 | 100 -> 110 (answer)
* */
return result;
}
}
As we can see this is not the best solution, because we are unnecessary iterating it over 32 times and it is also not that generalized. Which makes as to visit our next approach.
Using Bitwise operators (Optimized and Generalized):
So for this approach, I'll try to explain the approach, then code and then how to make it generalize.
We will take 2 flags(one, two) for analogy consider them as sets.
So we the number appears 1st time it will be added in one only if it is not present in two. and we will do the same for two, meaning if the number appears 2nd time we will remove it from 1 and then add it to two(only if it is not present in one) and for the number appearing a third time it will be removed from the set two and will no longer exist in either set.
You might have the question that why 2 sets(or variables) reason is explained in 4th point.
public int singleNumberOptimized(int[] A) {
int one = 0, two = 0;
/*
* Two sets to maintain the count the number has appeared
* one -> 1 time
* two -> 2 time
* three -> not in any set
* */
for(int arrIterator = 0; arrIterator < A.length; arrIterator++){
/*
* IF one has a number already remove it, and it does not have that number
* appeared previously and it is not there in 2 then add it in one.
* */
one = (one ^ A[arrIterator]) & ~two;
/*
* IF two has a number already remove it, and it does not have that number
* appeared previously and it is not there in 1 then add it in two.
* */
two = (two ^ A[arrIterator]) & ~one;
}
/*
* Dry run
* First Appearance : one will have two will not
* Second Appearance : one will remove and two will add
* Third Appearance: one will not able to add as it is there in two
* and two will remove because it was there.
*
* So one will have only which has occurred once and two will not have anything
* */
return one;
}
How to solve these type of questions more generically?
The number of sets you need to create depends on the value of k (Appearance of every other integer).
m >= log(K). (To count the number of 1's in the array such that whenever the counted number of 1 reaches a certain value, say k, the count returns to zero and starts over. To keep track of how many 1's we have encountered so far, we need a counter. Suppose the counter has m bits.) m will be the number of sets we need.
For everything else, we are using the same logic. But wait what should I return, the logic is to do OR operations with all the sets which will eventually the OR operation on the single number with itself and some 0s, which interns to the single number.
For a better understanding of this particular part go through this post here.
I have tried my best to explain to you the solution. Hope you like it. #HappyCoding
For more such content refer: https://thetechnote.web.app/
The idea is to reinterpret the numbers as vectors over GF(3). Each bit of the original number becomes a component of the vector. The important part is that for each vector v in a GF(3) vector space the summation v+v+v yields 0. Thus the sum over all vectors will leave the unique vector and cancel all others. Then the result is interpreted again as a number which is the desired single number.
Each component of a GF(3) vector may have the values 0, 1, 2 with addition being performed mod 3. The "one" captures the low bits and the "two" captures the high bits of the result. So although the algorithm looks complicated all that it does is "digitwise addition modulo 3 without carry".
Here is another solution.
public class Solution {
public int singleNumber(int[] nums) {
int p = 0;
int q = 0;
for(int i = 0; i<nums.length; i++){
p = q & (p ^ nums[i]);
q = p | (q ^ nums[i]);
}
return q;
}
}
Analysis from this blog post.
The code seems tricky and hard to understand at first glance.
However, if you consider the problem in Boolean algebra form, everything becomes clear.
What we need to do is to store the number of 1's of every bit. Since each of the 32 bits follow the same rules, we just need to consider 1 bit. We know a number appears 3 times at most, so we need 2 bits to store that. Now we have 4 state, 00, 01, 10 and 11, but we only need 3 of them.
In your solution, 01 for one and 10 for two are chosen. Let one represents the first bit, two represents the second bit. Then we need to set rules for one_ and two_ so that they act as we hopes. The complete loop is 00->10->01->00(0->1->2->3/0).
It's better to make Karnaugh map a.k.a. K-map. For Karnaugh Map Ref.
3-state counter
Respective values of A[i], two, one and two_, one_ after
0 0 0 | 0 0
0 0 1 | 0 1
0 1 0 | 1 0
0 1 1 | X X
1 0 0 | 0 1
1 0 1 | 1 0
1 1 0 | 0 0
1 1 1 | X X
Here X denotes we don't care for that case or simply in the final value of two and one, wherever their output is 1, that can also be considered, the result will be same and 4th and 8th case won't exist for it as two and one can't be one at the same time.
If you're thinking how I came up with the above table. I'm going to explain one of them. Considering 7th case, when A[i] is 1, two is 1 i.e. there already exists A[i] which repeats two times. Finally there is 3 A[i]'s. As, there's 3 of them, then two_ and one_ both should reset to 0.
Considering for one_
It's value is 1 for two cases i.e. 2nd and 5th case. Taking 1 is same as considering minterms in K-map.
one_ = (~A[i] & ~two & one) | (A[i] & ~two & ~one)
If ~two is taken common, then
(~A[i] & one) | (A[i] & ~one) will be same as (A[i]^one)
Then,
one_ = (one ^ A[i]) & ~two
Considering for two_
It's value is 1 for two cases i.e. 3rd and 6th case. Taking 1 is same as considering minterms in K-map.
two_ = (~A[i] & two & ~one) | (A[i] & ~two & one)
Bit manipulation for the calculated two_ will work for the problem. But, As you've mentioned
two_ = (A[i] & one) | (~A[i] & two)
The above expression can be easily be obtained using K-map considering don't cares i.e. X for all cases mentioned above as considering X won't affect our solution.
Considering for two_ and considering X
It's value is 1 for two cases i.e. 3rd and 6th case and X for two cases i.e. 4th and 8th case. Now, considering minterms.
two_ = (~A[i] & two & ~one) | (A[i] & ~two & one) | (~A[i] & two & one) | (A[i] & two & one)
Now, taking common (A & one) and (~A & two) in the above expression, you'll be left with (two|~two) and (one|~one) which is 1. So, we'll be left with
two_ = (A[i] & one) | (~A[i] & two)
For more insights!
There are three status: 0, 1, 2
So cannot use single bit, have to use high/low bit to present them as: 00, 01, 10
Here's the logic:
high/low 00 01 10
x=0 00 01 10
x=1 01 10 00
high is a function of both high and low.
If low == 1 then high = x, else high = high & ~x
We have
high = low & x | high & ~x
This equals to your: "int two_ = A[i] & one | ~A[i] & two;"
Similarly we have low as the function of both high and low:
If high == 1 then low = ~x, else low = low XOR x
I have a solution more straightforward:
int singleNumber(int A[], int n) {
int one = 0, two = 0, three = ~0;
for(int i = 0; i < n; ++i) {
int cur = A[i];
int one_next = (one & (~cur)) | (cur & three);
int two_next = (two & (~cur)) | (cur & one);
int three_next = (three & (~cur)) | (cur & two);
one = one_next;
two = two_next;
three = three_next;
}
return one;
}
First that came to my head, it's bigger but more simple to understand. Just implement addition mod by 3.
*
class Solution {
public:
int sum3[34], bit[33];
int singleNumber(int A[], int n) {
int ans(0);
for(int i=0;i<33;i++){
bit[i + 1] = 1<<i;
}
int aj;
for(int i=0;i<n;i++){
for(int j=1;j<33;j++){
aj = abs(A[i]);
if(bit[j] & aj) sum3[j]++;
}
}
for(int i=0;i<33;i++){
sum3[i] %= 3;
if(sum3[i] == 1) ans += bit[i];
}
int positve(0);
for(int i=0;i<n;i++){
if(A[i] == ans){
positve++;
}
}
if(positve%3 == 1)
return ans;
else return -ans;
}
};
*

Categories

Resources