preface
The operation of 0 and 1 is the bottom operation of the computer. All programs, no matter what language they are written in, must be transformed into a language that the machine can understand, that is, binary for basic operations, and these basic operations are the bit operations we want to talk about today. Because of the support of hardware, the computer is much faster than the ordinary decimal calculation. It is an important skill to realize the ordinary operation with the method of bit operation, which can greatly improve the program performance.
brief introduction
There are more than seven bit operations in the computer. Here, take Java as an example to explain the seven bit operators that need to be used in Java.
Symbol  describe  rule  give an example 

&  Bitwise AND  If the left and right sides are 1 at the same time, get 1, otherwise it is 0  1&1=1 1&0=0 
  Bitwise OR  As long as one of the left and right sides is 1, it returns 1, and it returns 0 only when both are 0  10=1 00=0 
^  Bitwise XOR  When the left and right sides are the same, it is 0, and the difference is 1  1^1=0 0^0=0 1^0=1 
~  Bitwise inversion  1 becomes 0, 0 becomes 1  ~1=0 ~0=1 
<<  Signed shift left  Keep the highest symbol, move the other bits to the left, and fill in the right with 0  1<<2=4 
>>  Signed right shift  Keep the highest bit symbol, move other bits to the right, and supplement with 0 except the highest bit  5>>1=2 10>>1=5 
>>>  unsigned right shift  All bits move to the left, and the high bits are filled with 0  5>>>1=2 10>>>1=2147483643 
Now that we talk about bit operations, we have to mention that in Javaint
For the representation of type numbers, Java’s int is a total of 32 bits, of which the 32nd symbol flag bit. If it is 0, it represents a positive number, and 1 represents a negative number. For example, the representation method of 1 is0000 0000 0000 0000 0000 0000 0000 0001
, the maximum can only be the result of setting the first 31 bits to 1, that is, $2 ^ {31} – 1 $; For the representation of negative numbers, it should be noted that instead of directly changing the highest bit of the corresponding positive number from 0 to 1, all bits are reversed and then added by one. The purpose of this is to make the sum of two binary numbers directly added to 0, such as1
The representation of is1111 1111 1111 1111 1111 1111 1111 1111
In this way, the final result of the binary addition of the two numbers is 0 (the highest bit overflow is discarded). The minimum value of a negative number is $2 ^ {31} $, and the absolute value is one bit higher than the maximum value of a positive number. Because this negative number is special, binary is expressed as1000 0000 0000 0000 0000 0000 0000 0000
, after taking the inverse plus one, it’s still itself.
By the way, here is a small skill of lower level operation, in which the principle can be guessed by yourself
Serial number  formula  Explain（n from0 (start) 

1  num = 1<<n  takenum The firstn Bit set to1

2  num &= ~(1<<n)  takenum The firstn Bit set to0

3  num ^= 1<<n  takenum The firstn Bit inversion 
4  num & (1<<n) == (1<<n)  inspectnum The firstn Whether the bit is1

5  num = num & (num1)  takenum Lowest1 Set0

6  num & num  getnum Lowest1

7  num &= ~((1<<n+1)1)  takenum mostn Position right0

8  num &= (1<<n)1  takenum The firstn Left position0

More operation related skills can be seen here.
Here’s the floating point typefloat
If you have a clear representation in Java, you can skip this part directly. Floating point numbers are 4 bytes in total, which can be expressed by the following formula:
$$ (1)^s \times m \times 2^{e127} $$
among

s
, the 31st bit. If it is 1, it represents a negative number, and 0 represents a positive number 
e
The 30th ~ 23rd bits refer to digits, representing an unsigned integer, with a maximum of 255 
m
, bits 220, mantissa, including hidden1
, indicating decimal places, the following invalid 0 should be removed
Like floating point numbers0.15625
The representation in binary is0011 1110 0010 0000 0000 0000 0000 0000
(using java code)Integer.toBinaryString(Float.floatToIntBits(0.15625F))
The binary representation of floatingpoint numbers can be obtained, but the highest bit is omitted0
）, where
 31st place
0
, indicating a positive number  The 30th to 23rd,
011 1110 0
Exponential bit, decimal is124
, minus 1273
 Bits 220,
010 0000 0000 0000 0000 0000
Mantissa, rounding off the number after the decimal0
Later get01
, plus the default 11.01
(decimal in binary)  To sum up, it is obtained according to the formula
0.15625
The binary formula of is $( 1) ^ 0 \ times (1.01) \ times2 ^ { 3} = 0.00101 $, and then converting binary to decimal becomes $2 ^ { 3} + 2 ^ { 5} = 0.125 + 0.03125 = 0.15625$
The calculation method of double type is the same as that of float, except that the index bit of double has 11 bits and the mantissa bit has 52 bits. 1023 needs to be subtracted when calculating the index. Compared with float, the accuracy of double is much higher. If you don’t care about space consumption, you’d better use double.
Leetcode related topics
Now we know the basic computer operation and the binary representation of numbers, so how to complete the calculation of decimal numbers through binary bit operation? Let’s find out one by one.
371 sum of two integers
Leetcode question 371 sum of two integers
Not usedoperator+
and
, calculate two integersa
、b
Sum of.
Example 1:
Input: a = 1, B = 2
Output: 3
Example 2:
Input: a = – 2, B = 3
Output: 1
There are more than 1900 dislikes on leetcode’s U.S. website. It seems that everyone has great opinions on this topic, but let’s take this opportunity to review how computers perform addition operations.
Review the decimal addition that we began to learn in primary school, such as15+7
, lowest5+7
obtain12
Yes10
Obtained by taking mold2
, carry1
, and then add the high bits1+0
Plus carry1
You get a high result2
, put it together22
。 This involves two numbers. One is the low order obtained by adding, that is5+7
Results obtained2
, the second is carry1
。 In binary calculation, it is necessary to obtain the low order and carry of the result through bit operation. For different cases, use a table to show that the two numbers area
andb
a  b  Low position  carry 

0  0  0  0 
1  0  1  0 
0  1  1  0 
1  1  0  1 
As you can see from the table above,Low = a ^ B
，Carry = A & B
。 This calculation may last many times. Recall that in decimal calculation, if the carry is always greater than 0, we have to calculate later. The same is true here. As long as the carry is not 0, we have to repeatedly calculate the low and carry (we need to move the carry to the left before the next calculation, so that the carry can operate with the higher bit) 。 At this timea
andb
It is the low bit and carry just calculated, which are expressed in the code of simple addition iteration:
public int getSum(int a, int b) {
if (a==0) return b;
if (b==0) return a;
int lower;
int carrier;
while (true) {
lower = a^b; // Calculate low order
carrier = a&b; // Calculate carry
if (carrier==0) break;
a = lower;
b = carrier<<1;
}
return lower;
}
29 divide two numbers
This is the division of two numbers in question 19 of leetcode
Given two integers, the divisordividend
Sum divisordivisor
。 Dividing two numbers requires no multiplication, division and divisionmod
Operator.
Returns the divisordividend
Divide by divisordivisor
Get the quotient.
Example 1:
Input: divide = 10, division = 3
Output: 3
Example 2:
Input: divide = 7, division = – 3
Output: – 2
explain:
 Both the dividend and divisor are 32bit signed integers.
 Divisor is not 0
 Suppose that our environment can only store 32bit signed integers with a value range of $[− 2 ^ {31}, 2^{31} − 1]$。 In this question, $2 ^ {31} is returned if the division result overflows − 1$。
In fact, this problem can be easily associated with the decimal division we often use. Here is an example to illustrate how to apply the idea of decimal division to binary.
Pictures are used33
divide6
, corresponding to binary100001
divide110
, there are three steps:
 Divide the divisor from
110
Start shifting left and right0
Until the maximum ratio is found100001
Small numbers11000
(right in the figure)0
It has been omitted). At this time, it moves two bits to the left, that is, times100
(binary), the remainder is1000
 Again
110
Move left to maximum ratio1000
Small numbers, at this time, are themselves, which is equivalent to multiplying by1
(moving left)0
Bits), the remainder is11
 Because the remainder is bigger than the divisor
110
If it is smaller, you can directly stop the operation and calculate the results from the above two stepsmultiplier（100
and1
）Add up to our final result（101
）。
Here we use java code to implement this logic:
public int divide(int dividendInt, int divisorInt) {
int shiftedDivisor; // Shifted divisor
int quotient = 0; // Record the quotient obtained by division
int remainder = dividendInt;
while (remainder>=divisorInt) {
int tempQuotient = 1; // Temporary business
dividendInt = remainder; // Process the remainder of the previous round
shiftedDivisor = divisorInt; // Reset divisor
while (dividendInt>=shiftedDivisor) {
shiftedDivisor <<=1;
tempQuotient <<= 1;
}
quotient += tempQuotient >> 1; // Cumulative calculated quotient
remainder = dividendInt  (shiftedDivisor >> 1); // The displacement priority is lower than the minus sign, and parentheses should be used
}
return quotient;
}
Through the loop method, we get the implementation logic of the division we want, but this method is only for both divisor and dividendPositive numberFor example, the divisor is100
The divisor is10
perhaps10
The returned result is0
！ about100
divide10
In this example, when comparing the size of the remainder and the shifted divisor, if they are both positive, it is normal to stop the cycle when the remainder is smaller than the divisor, but when they are all negative, there is a problem in doing so. The remainder is larger than the divisor, and the quotient is0
Therefore, the unequal sign direction of the termination conditions of the above two loops can be changed.
public int divide(int dividendInt, int divisorInt) {
int shiftedDivisor;
int quotient = 0;
int remainder = dividendInt;
While (remain < = divisorint) {// note that it becomes less than or equal to
int tempQuotient = 1;
dividendInt = remainder;
shiftedDivisor = divisorInt;
While (dividedint < = shifteddivisor) {// note that it becomes less than or equal to
shiftedDivisor <<=1;
tempQuotient <<= 1;
}
quotient += tempQuotient >> 1;
remainder = dividendInt  (shiftedDivisor >> 1);
}
return quotient;
}
Now we have both positive numbers and negative numbers. What about a positive number and a negative number? Then change the symbol to the same, and finally change it back when the result is returned. The title here kindly reminds us that we should consider the boundary problem when considering the conversion of symbols2147483648
The particularity of this value, that is, be careful when negative numbers become positive numbers, but positive numbers can become negative numbers at will, so it’s not as good as direct negative operation (refer to this article). Negative numbers are also used when accumulating the quotient obtained by each division1
To avoid overflow problems (e.g2147483648
divide1
Spillover problem).
When shifting the divisor, it should also be noted that the divisor cannot overflow after the shift. The best way to use is to judge whether the divisor is less than half of the minimum number before the shift (if it is shifted with a positive number, it should be judged whether it is greater than half of the maximum number). If it is less than, it will overflow in the next shift, At this time, the loop can only be terminated directly.
When judging the sign of the result, use the trick of one lower bit operation. When the XOR operation is mentioned above, if it is the same, it will be returned0
, otherwise1
Therefore, XOR the highest bits of two numbers. If yes0
It means that the result is a positive sign, otherwise it is a negative sign. In addition, there is an extreme case when the divisor takes the minimum value2147483648
And divisor1
The result is2147483648
It will overflow because there is only such a special case that can be directly excluded. The remaining numbers will not overflow anyway. The sorted code is as follows:
public int divide(int dividendInt, int divisorInt) {
if (dividendInt == Integer.MIN_VALUE && divisorInt == 1) {
return Integer.MAX_ VALUE; // For extreme cases, exclude directly and return the maximum value of int
}
boolean negSig =
((dividendInt ^ divisorInt) & Integer.MIN_VALUE) == Integer.MIN_ VALUE; // Determine whether the result is negative
dividendInt = dividendInt > 0 ?  dividendInt : dividendInt; // The divisor takes a negative value
divisorInt = divisorInt > 0 ?  divisorInt : divisorInt; // The divisor takes a negative value
int shiftedDivisor; // Shifted divisor
int quotient = 0; // Record the quotient obtained by division
int remainder = dividendInt;
int minShiftDivisor = Integer.MIN_ VALUE >> 1; // Prevent overflow. If it is greater than this value, it cannot be shifted to the left
while (remainder<=divisorInt) {
int tempQuotient = 1; // Temporary quotients are all treated as negative numbers
dividendInt = remainder; // Process the remainder of the previous round
shiftedDivisor = divisorInt; // Reset divisor
While (dividedint < = (shifteddivisor < < 1) // perform the next calculation only when it is smaller than the divisor
&&Shifteddivisor > = minshiftdivisor) {// judge whether overflow occurs after shifting
shiftedDivisor <<=1;
tempQuotient <<= 1;
}
quotient += tempQuotient; // Cumulative calculated quotient
remainder = dividendInt  shiftedDivisor; // Get the remainder and the next round as a new divisor
}
return negSig?quotient:quotient; // If it is a negative number, it will return the result directly. If it is not, it will be transformed into a positive number
}
191. Number of bit 1
Number of bit 1 in question 191 of leetcode
Write a function. The input is an unsigned integer and returns the number of digits in its binary expression1
Number of (also known as Hamming weight).
Example 1:
Input:
00000000000000000000000000001011
Output:3
Explanation: input binary string00000000000000000000000000001011
There are three digits’ 1 ‘in.
Example 2:
Input:
00000000000000000000000010000000
Output:1
Explanation: input binary string00000000000000000000000010000000
A total of one digit is’ 1 ‘.
The simplest way for anyone to solve this problem is to shift directly. In Java, you can directly use unsigned right shift to judge whether the lowest bit is right or not each time1
, judge as1
Just record all the times.
public int hammingWeight(int n) {
int count = 0;
for (int i = 0; i < 32; i++) {
count += n&1; // Accumulate 1
n>>>=1; // Cycle shift right 1 bit
}
return count;
}
But there is a more interesting solution to this problem. First, for a binary number, such as10100
, obtained after subtracting one10011
, compare the two numbers and find the lowest bit of the original number1
The number on the right of does not change, while the number on the right0
It’s all turned into1
, and this1
Become0
, if the original number and the number minus one are bitwise and, the lowest number will be1
Set zero.
So there’s a magical idea, if we want to put the numbersa
Lowest1
become0
Without changing other bits, directly througha&(a1)
You can get it, and put all the1
It’s all turned into0
Is not the number of bits1
Have you got the number of?
For example, for numbers101
, aftera&(a1) = 101&100 = 100
, just do it again100&011 = 0
, a total of two operations, and the final result becomes0
。
The simple code is as follows:
public int hammingWeight(int n) {
int count = 0; // Count the number of times to set 0
while (n!=0) {
count ++;
n = n&(n1); // Set the lowest 1 to 0
}
return count;
}
It seems that the above two algorithms can achieve the purpose we want, but we don’t know the efficiency. Let’s test and compare the builtin computing of Java1
Number method)
private void test() {
int t = 10000000; // Ten million times
long s = System.currentTimeMillis();
for (int i = 0; i < t; i++) {
hammingWeight1(3);
}
System.out.println("Java builtin:\t" + (System.currentTimeMillis()s));
s = System.currentTimeMillis();
for (int i = 0; i < t; i++) {
hammingWeight2(3);
}
System. Out. Println ("set the lowest 1 to 0: \ T" + (system. Currenttimemillis()  s));
s = System.currentTimeMillis();
for (int i = 0; i < t; i++) {
hammingWeight3(3);
}
System. Out. Println ("shift right comparison: \ T" + (system. Currenttimemillis()  s));
}
//Java builtin method
public int hammingWeight1(int n) {
return Integer.bitCount(n);
}
//Set the lowest 1 to 0
public int hammingWeight2(int n) {
int count = 0;
while (n!=0) {
count ++;
n = n&(n1);
}
return count;
}
//Shift right comparison
public int hammingWeight3(int n) {
int count = 0;
for (int i = 0; i < 32; i++) {
count += n&1; // Accumulate 1
n>>>=1; // Cycle shift right 1 bit
}
return count;
}
The output results are as follows:
Java builtin: 10
Lowest 1 set 0: 150
Shift right comparison: 10
Although the above is only the result of one test (the result is different every time you run the test), you can see the lowest position0
The efficiency of this method is one order of magnitude slower than the ordinary shift operation or the builtin method. I guess the reason should ben=n&(n1)
This operation is timeconsuming（n=n&(n1)
It’s actually two steps, the first stepint a = n1
, step twon=n&a
）, andn&1
perhapsn>>>=1
Both operations are much faster.
Back to the test, I found that the builtin Java method is sometimes much faster than shifting to the right, which is interesting. We have to see how it is implemented:
public static int bitCount(int i) {
// HD, Figure 52
i = i  ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
return i & 0x3f;
}
After reading the sentencewhat the fuckCome to my mind, what’s this writing?! What immortal algorithm is this! Let’s take a closer look at the algorithm and decompose each step, assuming that our input is1
Public static int bitcount (int i) {// I = Binary of 11 11 11 11 11 11 11 11 11  1
// HD, Figure 52 // 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
i = i  ((i >>> 1) & 0x55555555); // I = 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
// 00 11 00 11 00 11 00 11 00 11 00 11 00 11 00 11
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333); // I = 0100 0100 0100 0100 0100 0100 0100 0100 0100 (2) sum every 4 bits
// 0000 1111 0000 1111 0000 1111 0000 1111
i = (i + (i >>> 4)) & 0x0f0f0f0f; // I = 000010000 000010000 (3) sum every 8 bits
i = i + (i >>> 8); // I = 0000110000000000 0001000000010000 (4) sum every 16 bits
i = i + (i >>> 16); // I = 00000100000010000001000000100000010000000000 (5) sum every 32 bits
return i & 0x3f; // I = 00000000000000000000000000000 (6) take the lowest 6 digits
}
There are six steps in this process, and the main idea isDivide and conquer, calculate every 2, 4, 8, 16, 32 bits1
Number of:
 The first and most important step is to count the numbers in every 2 digits
1
Number of, such as binary11
There are two1
It should become a statistical result10
（11((11>>>1)&01) = 10
），10
perhaps01
Should become01
（10((10>>>1)&01) = 01
，01((01>>>1)&01) = 01
）  Count the number in every four digits
1
The number of, that is, the two digits calculated above1
The number and sum of, for example01 00
, by shift and mask0011
Bitwise and, become0000
and0001
Then sum it up0001
 Statistics of every 8bit binary
1
The number of binary digits in this step is different from that in the above step. Instead of adding with a mask first, add first and then mask. The main difference is that in the previous step, the addition of two two binary digits may overflow. After using a mask, you will get wrong results, such as10 10
, add to get01 00
Then use00 11
Bitwise and get00 00
Not what we want. When calculating the number of 8 bits, it will not overflow, because it is in 4 bits1
The maximum number of is 4, that is0100
, the maximum sum of the two is1000
, it will not carry to the second 4 bits. Using the mask can get the correct result and clear the redundant data1
 Statistics per 16 bit binary
1
At this time, the direct shift addition does not use a mask. The reason is very simple. The result of every 8 bits in the previous step is saved in the last 4 bits and must be accurate. The direct addition will not overflow 8 bits, and the result must be saved in the rightmost 8 bits. We don’t care about the value of the left 8 bits in the 16 bits, Therefore, there is no need to use a mask, and it will not affect the subsequent calculation  In this step, the sum of 32 bits is obtained and directly shifted and added, because the number of 1 of the left and right 16 bits must be saved in their respective right 8 bits, and the addition result will not overflow. It must still be in the rightmost 8 bits, and the 24 bits on the left have no effect
 The result must be in the last 6 bits, because there are only 32 at most
1
, only 6 bits are needed to save this value.
In this way, the final result is obtained by using the divide and conquer method through a fine binary operation1
I have to sigh that this is really wonderful!
There are many subtle bit operation methods of integer numbers in Java, such as the following. Although I would like to introduce them, I will skip them because of space, because there are more important contents later
highestOneBit
lowestOneBit
numberOfLeadingZeros
numberOfTrailingZeros
reverse
rotateLeft
rotateRight
268 missing number
Missing number in question 268 of leetcode
Given a containing0, 1, 2, ..., n
inn
Number of sequences, find out0 .. n
The number that does not appear in the sequence.
Example 1:
Input: [3,0,1]
Output: 2
This problem can use hash table or summation method, which is a good method, but since this article is about bit operation, let’s use the classical bit operation.
For the bit operation of numbers, bitwise XOR has a very important property, for numbersa
andb
yes:
a^a=0
a^0=a
a^b^a=b
By analogy, we can find that if bitwise XOR is performed for each element in an array, the elements with even frequency will become0
, if the occurrence frequency of each element in the array is an even number of times, the result of bitwise XOR of the whole array is0
, if only one element occurs an odd number of times, the result of bitwise XOR is this element.
Back to this question, how many times do all the numbers in the array appear1
, the number that does not appear is0
Obviously, we can’t directly bitwise XOR, so let’s add one after this array0..n
The array contains all the elements. When the two numbers are combined, the number of occurrences of the original number is2
, and the number of times that the original number did not appear is1
, you can use bitwise XOR.
However, there is no need to explicitly add an array here. Instead, XOR is performed inside the loop. The code is as follows:
public int missingNumber(int[] nums) {
int xor = 0;
for (int i = 0; i < nums.length; i++) {
xor ^= i^nums[i]; // Try to add new arrays by bit XOR virtual inside the loop
}
return xor^nums.length; // Make up the last digit n missed in the cycle
}
136 a number that appears only once
A number that appears only once in question 136 of leetcode
Given aNon emptyAn array of integers. Each element appears twice except that one element appears only once. Find the element that appears only once.
explain：
Your algorithm should have linear time complexity. Can you do it without using extra space?
Example 1:
Input: [2,2,1]
Output: 1
According to the idea of bitwise XOR in the above question, you can write the result with your eyes closed:
public int singleNumber(int[] nums) {
int num = 0;
for (int i : nums) {
num ^= i;
}
return num;
}
137 number II that appears only once
This is the number II that appears only once in question 137 of leetcode
Given aNon emptyInteger array, except that an element appears only once, every other element appears three times. Find the element that appears only once.
explain:
Your algorithm should have linear time complexity. Can you do it without using extra space?
Example 1:
Input: [2,2,3,2]
Output: 3
This question seems to be very similar to the one above, except that it originally appears2Once, now it has become3The original XOR operation can makea^a=0
, if there is an operation symbol that makesa?a?a=0
, then the problem will be solved. It seems that there is no such operator, so think of other methods.
First, let’s look at the characteristics of the XOR operator,1^1=0
、0^1=1
、1^0=1
、0^0=0
, think of addition,01+01=10
Take the low order as0
, so it’s actually adding left and right operators to remove carry (equivalent to modulo 2). If you want three1
Add to get0
, then add it in decimal, and then3
Just take the mold.
In this way, each bit of each digital binary bit in the array is added, and finally3
Take the module and get the result of each binary bit of the number that appears only once. The code of the preliminary idea is as follows:
public int singleNumber(int[] nums) {
int bit;
int res = 0;
for (int i = 0; i < 32; i++) {
bit = 0;
For (int num: Num) {// calculate the number of 1s in bit I
bit += (num>>i)&1;
}
res = (bit%3)<<i; // The result is obtained by taking the modulus according to the number of 1
}
return res;
}
In fact, this is also a general solution. The number of times here is 3. If it is changed to 4 or 5 times, it can also be solved by this method. I have read many other people’s solutions, and there is a more exquisite solution. Refer to here.
In the above solution, we use onebit
To save the sum of one bit of all numbers, and each element isint
Type, but what is the maximum number of repetitions of this problem3Moreover, the final result we need is not the sum, but the modulus of sum to 3. Therefore, if we can take the modulus continuously in the calculation process, we can control the sum of each bitLess than 3, up to 2bit binary numbers are OK, and 32bit binary numbers are not requiredint
To save. Although there is no binary number with only 2 bits in Java, it can be represented by two 1bit binary numbers, so the whole array uses twoint
The numeric representation of type is OK. Another problem with the above solution is that the entire array is traversed 32 times, because each bit needs to be traversed, but if two are usedint
To represent, with appropriate bit operation, the number of traversals can be reduced to one!
First uselower
andhigher
It represents the low and high bits of this binary number. The change when encountering a binary number each time can be represented by the following figure (0 is obtained by modulo when encountering 3, so there can be no change)lower=1 higher=1
This state can only be a transitional state in the middle).
num  higher(old)  lower(old)  Higher (transition)  Lower (transition)  Mask (mask)  higher(new)  lower(new) 

0  0  0  0  0  1  0  0 
0  0  1  0  1  1  0  1 
0  1  0  1  0  1  1  0 
1  0  0  0  1  1  0  1 
1  0  1  1  0  1  1  0 
1  1  0  1  1  0  0  0 
Do you feel a little confused and how to turn such a form into a formula?
First, let’s take a look at the transition from the old state to the transition state. It is completely a binary addition, and the low value is based onlower
andnum
The transition state that can be obtained islower=lower^num
； The highorder value needs to get the loworder carry, that islower&num
Then add the original high positionhigher^(lower&num)
, the high and low positions of the transition state can be easily calculated through these two parts.
Transition states can occurhigher=1 lower=1
If it occurs 4 times, the problem can be solved directly. The final new state can be obtained without any additional operation, but what we require here is 3 times, that is, whenhigher=1 lower=1
It is necessary to set the two bits to zero at the same time, which will remain unchanged in other states. At this time, we need to use the mask. First calculate the mask, and then the transition state through the maskcorrectInto the final state. The mask is determined according to the high and low bits of the transition state. If the number composed of the high and low bits of the transition state reaches the desired threshold (3 in this question), the mask becomes0
, high and low positions are carried out at the same time&
Operation set to zero; When you don’t reach it1
, use&
Operation is equivalent to maintaining the original value. You can see this problem whenhigher=1 lower=1
Time maskmask=0
, other timesmask=1
, very familiar operation, isn’t thismask=~(higher&lower)
Oh, my God! This problem has come to the bottom!
The last new state is directly bitwise and with the transition state and mask,higher=higher&mask
andlower=lower&mask
The new value is reached.
After traversing the entire array, the number calculated three times appearshigher
andlower
It must be 0. There must be a number oncehigher
It must also be 0, andlower
The low bit is the value of the binary bit of the number that appears once, so it is obtained finallylower
Is the required return result.
public int singleNumber(int[] nums) {
int higher = 0, lower = 0, mask = 0;
for (int num : nums) {
higher = higher^(lower&num);
lower = num^lower;
mask = ~(higher&lower); // Compute mask
higher &=mask;
lower &= mask;
}
return lower;
}
The above solution process is simpler. First, the transition state is obtained by adding, and then the final new state is calculated by mask. For any problem that occursk
The problem of finding numbers that only appear once in the array of times can be used. There are only two bits (one high and one low). Ifk=5
, then 2 digits is not enough, and 3 digits are neededs1
、s2
ands3
, and the calculation of the mask becomesmask = ~(s3&~s2&s1)
(when the transition state is101
The mask is0
）。
If the calculation of the above mask becomesmask=~(higher&~lower)
, this code can be put directly intoA number that appears only onceIn this problem.
In addition to using transition states, you can also use Karnaugh map to directly solve the problem of new and old state transformation. See this post for specific problemsolving methods.
260 number III that appears only once
This is the number III that appears only once in question 260 of leetcode
Given an array of integersnums
, where exactly two elements appear only once and all other elements appear twice. Find the two elements that appear only once.
Example:
Input: [1,2,1,3,2,5]
Output: [3,5]
be careful:
 The order in which the results are output is not important. For the above example,
[5, 3]
That’s the right answer.  Your algorithm should have linear time complexity. Can you just use constant space complexity?
The difference between this problem and the above problem is that the occurrence times of the elements to be solved above are only once, and the last element can be obtained. However, this problem needs to solve two elements that occur once. For example, these two elements area
andb
, the result of a bitwise XOR traversal isa^b
, it seems that we can’t draw any conclusion from this information.
Since we need to traverse twice to get two numbers, if we traverse both times, the information we want will be mixed together. The only way is to divide the array into two sub arrays, one containinga
, the other containsb
In this way, we can get the desired result by traversing separatelya
andb
Yes.
To split this array, you need to distinguisha
andb
, becausea
andb
It must be different. There must be 1 bit in the 32 bits of binary representation. Find this bit, and then set this bit in the whole array as1
The sum of is0
Numbers are listed as two sub arrays (the same number will certainly be divided into the same sub array), and the results can be obtained by XOR respectively. To finda
andb
Different binary bits, obtained abovea^b
It can come in handy. The XOR result is1
It must be the one with two different numbers. You can distinguish it by looking for any one. Here we directly1
The lowest order of the. At the beginning of the article, you can get the lowest order1
Operation of——num&(num)
, can be used directly. The simplified code is as follows:
public int[] singleNumber(int[] nums) {
if (nums == null  nums.length < 1) return null;
int[] res = new int[2];
int xor = 0;
For (int num: Num) {// calculate a ^ B
xor = xor^num;
}
int bits = xor & (xor); // Get lowest 1
For (int num: nums) {// get the number a of occurrence times bit 1
res[0] ^= (bits & num) == bits ? num : 0;
}
res[1] = res[0]^xor; // Get another number B from the previous number
return res;
}
338 bit count
This is the bit count in question 338 of leetcode
Given a nonnegative integernum
。 about0 ≤ i ≤ num
Each number in the rangei
, calculates the number in its binary number1
And return them as an array.
Example 1:
Input: 2
Output: [0,1,1]
Example 2:
Input: 5
Output: [0,1,1,2,1,2]
Advanced:
 The time complexity is given asO(n*sizeof(integer))The answer is very easy. But you can in linear timeO(n)Can you do it with a scan inside?
 The space complexity of the algorithm is required to beO(n)。
After reading this question and seeing the final advanced part, do you feel familiar – the problem needs to be solved in linear time, and the spatial complexity is O (n) – isn’t this dynamic programming! Think about the characteristics of the problem and find the optimal substructure.
For a binary numbern
, if you want to get his number from left to rightn
In bit1
You can get its number from left to right firstn1
In bit1
Then according to the number ofn
Whether the bit is1
To decide whether to add1
。 To get the number in the whole number1
You need to know the number from left to right31
Bit (from1
Start count)1
The number of and whether the lowest order is1
。 It is not difficult to get the former, because if you move the whole number one bit to the right, it is a previously calculated number (dynamic programming starts from small to large), which becomes the optimal substructure and the recursive formula becomesres[i] = res[i>>1] + (i&1);
, with this formula, the problem is solved.
For example, if you want to get10
That is, binary1010
of1
You can find the three binary digits on the left first101
of1
The number of, plus the rightmost bit0
That’s it.
public int[] countBits(int num) {
int[] res = new int[num+1]; // No initialization is required. The default value is 0
for (int i = 0; i < res.length; i++) {
res[i] = res[i>>1] + (i&1);
}
return res;
}
187 repeated DNA sequences
This is the DNA sequence repeated in question 187 of leetcode
All DNA consists of a series of nucleotides abbreviated as a, C, G and T, such as “acgaattccg”. When studying DNA, identifying repetitive sequences in DNA can sometimes be very helpful.
Write a function to find all 10 letter long sequences (substrings) that appear more than once in DNA molecules.
Example:
Input: S = “aaaacccccaaaaccccccaaaggttt”
Output: [“aaaaccccc”, “cccccccaaaa”]
Seeing so many obvious problems of bit operation in front of me, I feel a little hoodwinked when I jump to this problem. It seems that it has nothing to do with bit operation. But pay attention to the reading questions. There are two key qualifications——10 letter long sequenceandOnly “ACGT” has four characters, when you see these two conditions, you think of oneint
The number has 32 bits, so oneint
Numbers can just represent such a 10 character sequence.
In implementation, we use

00
representativeA

01
representativeC

10
representativeG

11
representativeT
Such as sequenceAAAAACCCCC
You can use it00 00 00 00 00 01 01 01 01 01
To show that this is only 20 bits from right to left, and the higher bits are0
Omitted.
A string of DNA needs exactly 20 bits, and the high bits are directly removed with a mask. Each unique DNA string can use a uniqueint
Number representation. An array is used to represent the number of occurrences of each string. The maximum length of the array is1<<20
。
public List<String> findRepeatedDnaSequences(String s) {
if (s == null  s.length() <= 10) return new ArrayList<>();
char[] chars = s.toCharArray(); // Convert to array to improve efficiency
int[] freq = new int[1<<20]; // Frequency array
int num = 0; // Int value during calculation
int mask = (1<<20)1; // Mask, only the lowest 20 bits are reserved
For (int i = 0; I < 10; I + +) {// initialize the first DNA string
num <<= 2;
if (chars[i] == 'C') {
num = 1;
} else if (chars[i] == 'G') {
num = 2;
} else if (chars[i] == 'T') {
num = 3;
}
}
freq[num]++;
List<Integer> repeated = new ArrayList<>();
For (int i = 10; I < chars. Length; I + +) {// traverse all DNA strings with length of 10
num <<= 2; // Clear the top two bits, that is, remove the slipped string
if (chars[i] == 'C') {
num = 1;
} else if (chars[i] == 'G') {
num = 2;
} else if (chars[i] == 'T') {
num = 3;
}
num &= mask; // The mask reserves the lowest 20 bits
freq[num]++; // Statistical frequency
if (freq[num] == 2) repeated.add(num); // Only when the number of occurrences is 2 can it be included to avoid repetition
}
List<String> res = new ArrayList<>(repeated.size());
For (integer: repeated) {// convert int number into DNA string
char[] seq = new char[10];
for (int i = 9; i >= 0; i) {
switch (integer&3) {
case 0:seq[i]='A';break;
case 1:seq[i]='C';break;
case 2:seq[i]='G';break;
case 3:seq[i]='T';break;
}
integer >>=2;
}
res.add(new String(seq));
}
return res;
}
summary
This article mainly explains several basic methods and tricks of binary bit operation, and mentions the representation of floatingpoint numbers, hoping to increase the understanding of the underlying data of the computer.
Later, we talked about some classic topics above leetcode, such asDivide two numbersandA number that appears only once, they all use bit operation to solve practical problemsRepetitive DNA sequenceIt is a higherlevel case of solving problems through bit operation.
I have written thousands of words, hoping to help you deepen your understanding of bit operation and skillfully apply it in work and study.
reference resources
A summary: how to use bit manipulation to solve problems easily and efficiently
Bit Manipulation 4% of LeetCode Problems
Bit Twiddling Hacks
Bitwise operators in Java
9.1 Floating Point
Binary format analysis of Java floating point number
How is a floating point number represented in Java?
Execution time 1ms, defeat 100%
Detailed popular thinking analysis, multi solution
Detailed explanation and generalization of the bitwise operation method for single numbers
Bitwise Hacks for Competitive Programming
Bit Tricks for Competitive Programming
For more information, please see myPersonal blog