Algorithm brushing -- bit operation

Code 1 : Power of Two

Given an integer n, return true if it is a power of two. Otherwise, return false.

An integer n is a power of two, if there exists an integer x such that n == 2x.

Example 1

Input: n = 1
Output: true
Explanation: 2^0 = 1

Example 2

Input: n = 16
Output: true
Explanation: 2^4 = 16

Example 3

Input: n = 3
Output: false

Example 4

Input: n = 4
Output: true

Example 5

Input: n = 5
Output: false

Solution

Conventional thinking

class Solution {
public:
    bool isPowerOfTwo(int n) {
        if(n==0) return false;
		while(n%2==0){
			n/=2;
		}
		if(n!=1) return false;
		else return true;
    }
};

In fact, loop is used. The original intention of this problem is to use bit operation.

Bit operation

class Solution {
public:
    bool isPowerOfTwo(int n) {
        if (n<=0) return false;
		if (n&(n-1)) return false;
		else return true;
    }
};

  • Common bit operation

Judge parity

(X & 1) = = 1 - equivalent - > (x% 2 = = 1)
(X & 1) = = 0 - equivalent - > (x% 2 = = 0)
x / 2 - equivalent - > x > > 1
X & = (x - 1) ---- > remove the lowest binary 1 of X
X & - x ----- > get the lowest 1
x & ~x -----> 0

Bit operation at specified position

Clear the rightmost n bits of X: X & (~ 0 < < n)
Get the nth bit value of X: (x > > n) & 1
Get the power of the nth bit of x: x & (1 < < n)
Only the nth position is 1: X | (1 < < n)
Only the nth position is 0: X & (~ (1 < < n))
Clear the highest bit of x to the nth bit (inclusive): x & ((1 < < n) - 1)
Clear bits n to 0 (inclusive): X & (~ ((1 < < (n + 1)) - 1))

Exclusive or combination law

x ^ 0 = x, x ^ x = 0
x ^ (~0) = ~x, x ^ (~x) = ~0
a ^ b = c, a ^ c = b, b ^ c = a

This question X & (x - 1) is equivalent to removing the lowest 1 of X to judge whether it is all 0 (the multiple of two in binary has only one 1)

Code 2 : Number of 1 Bits

Write a function that takes an unsigned integer and returns the number of '1' bits it has (also known as the Hamming weight).

Example 1

Input: n = 00000000000000000000000000001011
Output: 3
Explanation: The input binary string 00000000000000000000000000001011 has a total of three '1' bits.

Example 2

Input: n = 00000000000000000000000010000000
Output: 1
Explanation: The input binary string 00000000000000000000000010000000 has a total of one '1' bit.

Example 3

Input: n = 11111111111111111111111111111101
Output: 31
Explanation: The input binary string 11111111111111111111111111111101 has a total of thirty one '1' bits.

Solution

Remove the last 0

class Solution {
public:
    int hammingWeight(uint32_t n) {
    	int count=0;
    	while(n){ 
			n&=(n-1);
			count++;
		}  
		return count;
    }
};

Inspired by the last question, the last 0 is continuously removed, and the record is removed several times until n is all 0.

Loop to check whether each bit is 1

class Solution {
public:
    int hammingWeight(uint32_t n) {
    	int count=0;
    	while(n){ 
    		count+=(n&1);
    		n>>=1;
		}
		return count;
    }
};

Note the shift right symbol > > =, taking the last digit n&1.

Code 3 : Reverse Bits

Reverse bits of a given 32 bits unsigned integer.

Follow up : If this function is called many times, how would you optimize it?

Example 1

Input: n = 00000010100101000001111010011100
Output:    964176192 (00111001011110000010100101000000)
Explanation: The input binary string 00000010100101000001111010011100 represents the unsigned integer 43261596, so return 964176192 which its binary representation is 00111001011110000010100101000000.

Example 2

Input: n = 11111111111111111111111111111101
Output:   3221225471 (10111111111111111111111111111111)
Explanation: The input binary string 11111111111111111111111111111101 represents the unsigned integer 4294967293, so return 3221225471 which its binary representation is 10111111111111111111111111111111.

Solution

ergodic

using namespace std;
class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
    	uint32_t ans=0;
        for(int i=31;i>=0;i--){
        	ans+=((n>>i)&1)*pow(2,31-i);
		}
		return ans;
    }
};

The general idea of traversing forward from the last (note that (n > > i) & 1 means the ith of n)

move

class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
    	uint32_t ans=0;
    	for(int i=0;i<32;i++){
    		ans=(ans<<1)|(n&1);
    		n>>=1;
		}
		return ans;
    }
};

Move ans to the left one at a time, add the last one of n to ans (at this time, the last bit of ANS is 0, and the union set can be added directly), and then move n to the right one.

Divide and conquer (not so understood)

class Solution {
private:
    const uint32_t M1 = 0x55555555; // 01010101010101010101010101010101
    const uint32_t M2 = 0x33333333; // 00110011001100110011001100110011
    const uint32_t M4 = 0x0f0f0f0f; // 00001111000011110000111100001111
    const uint32_t M8 = 0x00ff00ff; // 00000000111111110000000011111111

public:
    uint32_t reverseBits(uint32_t n) {
        n = n >> 1 & M1 | (n & M1) << 1;
        n = n >> 2 & M2 | (n & M2) << 2;
        n = n >> 4 & M4 | (n & M4) << 4;
        n = n >> 8 & M8 | (n & M8) << 8;
        return n >> 16 | n << 16;
    }
};

Divide and rule, first two two exchanges, then four four exchanges... The last sixteen sixteen exchanges.

Code 4 : Single Number

Given a non-empty array of integers nums, every element appears twice except for one. Find that single one.

You must implement a solution with a linear runtime complexity and use only constant extra space.

Example 1

Input: nums = [2,2,1]
Output: 1

Example 2

Input: nums = [4,1,2,1,2]
Output: 4

Example 3

Input: nums = [1]
Output: 1

Solution

Use map

class Solution {
public:
   int singleNumber(vector<int>& nums) {
   	int n=nums.size();
   	int ans;
   	map<int,bool> a;
   	for(int i=0;i<n;i++){
   		if(a.find(nums[i])!=a.end()){
                a[nums[i]]=false;
           }
   		else{
                a[nums[i]]=true;
           }
   	}
   	for(auto it=a.begin();it!=a.end();it++) {
           if (it->second) ans=it->first;
       }
   	return ans;
   
   }
};

Pay attention to the use of map

  • Determine whether a.find (Num [i]) exists= a. End() (end is returned if it does not exist)
  • Can be inserted directly (no need to use insert())
  • Iterator traverses for (auto, it = a.begin(); it! = a.end(); it + +), finds key with first(), finds value with second()

XOR algorithm

class Solution {
public:
    int singleNumber(vector<int>& nums) {
    	int ans=nums[0];
		for(int i=1;i<nums.size();i++){
			ans^=nums[i];
		}
		return ans;
	}
};

In the XOR operation, the same is 0. This algorithm will finally turn the same into 0, and then 0 and the XOR of any number are any number.

Tags: Algorithm leetcode

Posted on Tue, 21 Sep 2021 04:06:05 -0400 by Stingus