Leetcode.Bit Manipulation.位运算专题.(持续更新)

1. 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).web

For example, the 32-bit integer ‘11’ has binary representation 00000000000000000000000000001011, so the function should return 3.数组

题目大意:
计算一个32位整型数的二进制表示中1出现的次数。app

解题思路:
1.判断每一个二进制位,统计1出现次数。
2.每次从全部二进制位中去掉一个1直到没有。
3.打表法。ide

//判断每一个二进制位,统计1出现次数。
int hammingWeight(uint32_t x) {
    int count = 0;
    for(; x; x >>= 1)
        count += x&1;
    return count;
}
//每次从全部二进制位中去掉一个1直到没有。
int hammingWeight(uint32_t x) {
    int count = 0;
    for(; x; count++)
        x &= x - 1;    // 去掉x二进制表示中末尾的1
    return count;
}
//打表法。
int _[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};    // 全部4-bit整数二进制中1的个数
int hammingWeight(uint32_t x) {
    int count = 0,m;
    for(m = 8; m--;  x>>= 4)    // 每次对表查找末四位,共8次
        count += _[x&15];
    return count;
}

2. Power of Two

Given an integer, write a function to determine if it is a power of two. svg

题目大意:
判断一个数是否为2的幂。ui

解题思路:
1.判断该数二进制表示中是否只有一个1。this

//判断该数二进制表示中是否只有一个1。
bool isPowerOfTwo(int n) {
    return n > 0 && !(n & n - 1);
}

3. Reverse Bits

Reverse bits of a given 32 bits unsigned integer.
For example, given input 43261596 (represented in binary as 00000010100101000001111010011100), return 964176192 (represented in binary as 00111001011110000010100101000000).spa

题目大意:
反转一个32位整数的二进制表示。code

解题思路:
1.将该数二进制表示逆向拷贝到另外一个数。
2.二分法交换相邻区块。xml

//将该数二进制表示逆向拷贝到另外一个数。
uint32_t reverseBits(uint32_t n) {
    uint32_t x;
    for(int i = 32; i--; n >>= 1){
        x <<= 1;
        x |= n&1;
    }
    return x;
}
//二分法交换相邻区块。
uint32_t reverseBits(uint32_t x) {
    x = ((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16);    //交换前16位与后16位
    x = ((x & 0xff00ff) << 8) | ((x & 0xff00ff00) >> 8);    //交换每16位的前8位与后8位
    x = ((x & 0xf0f0f0f) << 4) | ((x & 0xf0f0f0f0) >> 4);    //交换每8位的前4位与后4位
    x = ((x & 0x33333333) << 2) | ((x & 0xCCCCCCCC) >> 2);    //交换每4位的前2位与后2位
    x = ((x & 0x55555555) << 1) | ((x & 0xAAAAAAAA) >> 1);    //交换每2位的前1位与后1位
    return x;
}

4. Single Number

Given an array of integers, every element appears twice except for one. Find that single one.

题目大意:
给出一个整型数组,该数组中除一个元素外其他元素均出现两次,找出只出现一次的元素。

解题思路:
1.统计全部数字出现次数。
2.统计每一个二进制位上1出现的次数,出现奇数次的位构成只出现一次的数。
3.对每个数进行一次异或运算,最终将保留只出现一次的数。

//统计全部数字出现次数。
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        map<int, int> s;
        for (int i = 0; i < nums.size();s[nums[i++]]++);
        for (auto i = s.begin(); i != s.end(); i++)
            if (i->second == 1)
                return i->first;
    }
};
//统计每一个二进制位上1出现的次数,出现奇数次的位构成只出现一次的数。
int singleNumber(int* nums, int numsSize) {
    int s[32] = {0}, i, j, x;
    for (i = 0; i < numsSize; i++)
        for (j = 0; j < 32; j++)
            s[j] += (nums[i] >> j) & 1;
    for (x = i = 0; i < 32; i++)
        x = (x<<1) | s[31 - i] & 1;
    return x;
}
// 对每个数进行一次异或运算,最终将保留只出现一次的数(不使用额外空间)。
int singleNumber(int* nums, int numsSize) {
    for(;--numsSize;*nums ^= nums[numsSize]);
    return *nums;
}

5. Single Number II

Given an array of integers, every element appears three times except for one. Find that single one.

题目大意:
给出一个整型数组,该数组中除一个元素外其他元素均出现3次,找出只出现1次的元素。

解题思路:
1.统计全部数字出现次数。
2.统计每一个二进制位上1出现的次数,出现非3的倍数次的位构成只出现一次的数。
3.位运算储存出现1,2,3次的位(详情见代码)。

//统计全部数字出现次数。
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        map<int, int> s;
        for (int i = 0; i < nums.size();s[nums[i++]]++);
        for (auto i = s.begin(); i != s.end(); i++)
            if (i->second == 1)
                return i->first;
    }
};
//统计每一个二进制位上1出现的次数,出现非3的倍数次的位构成只出现一次的数。
int singleNumber(int* nums, int numsSize) {
    int s[32] = {0}, i, j, x;
    for (i = 0; i < numsSize; i++)
        for (j = 0; j < 32; j++)
            s[j] += (nums[i] >> j) & 1;
    for (x = i = 0; i < 32; i++)
        x = (x<<1) | s[31 - i] % 3;
    return x;
}
// 位运算储存出现1,2,3次的位
int singleNumber(int* nums, int numsSize) {
    int a,b,c,i;//a,b,c分别存储出现1,2,3次的位
    for(a = b = c = i = 0; i < numsSize; i++){
        b ^= a & nums[i];//将出现2次的位加入b
        a ^= nums[i];//异或运算清除a中出现两次的位
        c = a & b; //取得出现了3次的位
        a &= ~c;//从a中清除出现3次的位
        b &= ~c;//从b中清除出现3次的位
    }
    return a;
}

6. Single Number III

Given an array of numbers nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.

For example:
Given nums = [1, 2, 1, 3, 2, 5], return [3, 5].
The order of the result is not important. So in the above example, [5, 3] is also correct.

题目大意:
给出一个整型数组,该数组中除2个元素外其他元素均出现2次,找出只出现1次的这2个元素,顺序任意。

解题思路:
1.统计全部数字出现次数。
2.设两个只出现一次的元素为a、b,全部数字的异或为x,显然x等于a异或b,则x中为1的二进制位表示a和b中不一样的二进制位,取x中任意1位,则a和b中有且只有一个数的这一位为1,则数组中全部该位为1的数字的异或结果为a或b,该结果与x异或运算可得另外一个元素。

//统计全部数字出现次数。
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        map<int, int> s;
        for (int i = 0; i < nums.size();s[nums[i++]]++);
        for (auto i = s.begin(); i != s.end(); i++)
            if (i->second == 1)
                return i->first;
    }
};
int* singleNumber(int* nums, int numsSize, int* returnSize) {
    int *r = (int*)malloc(sizeof(int) << 1);
    int i,x,z,t;
    for (i = x = 0;i < numsSize; i++)
        x ^= nums[i];
    //此时x为两个目标元素的异或
    z = x&~(x - 1); //取x的最右边为1的位
    for (t = i = 0; i < numsSize; i++)
        if(nums[i]&z) //全部该位为1的数参与异或运算
            t ^= nums[i];
    //此时t为两个目标元素中的一个
    r[0] = t;
    r[1] = x^t;
    *returnSize = 2;
    return r;
}

7. Missing Number

Given an array containing n distinct numbers taken from 0, 1, 2, …, n, find the one that is missing from the array.
For example,
Given nums = [0, 1, 3] return 2.

题目大意:
给出一个整型数组,该数组包含0~n的其中n个数,求缺失的那个数。

解题思路:
1.对数组从小到大排序,遍历数组,返回那个与下标不等的元素。
2.对整个数组求异或,而后用其结果继续对0~n的数字求异或,则数组中出现的元素被异或两次清除。

//对数组从小到大排序,遍历数组,返回那个与下标不等的元素。
class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int i;
        sort(nums.begin(),nums.end());
        for(i = 0; i < nums.size(); i++)
            if(i != nums[i])
                return i;
        return i;
    }
};
//对整个数组求异或,而后用其结果继续对0~n的数字求异或,则数组中出现的元素被异或两次清除。
int missingNumber(int* nums, int numsSize) {
    int x = numsSize;
    for(int i = 0; i < numsSize; i++)
        x ^= i ^ nums[i];
    return x;
}

8. Bitwise AND of Numbers Range

Given a range [m, n] where 0 <= m <= n <= 2147483647, return the bitwise AND of all numbers in this range, inclusive.

For example, given the range [5, 7], you should return 4.

题目大意:
求区间[m, n]中全部整数的按位与运算结果。

解题思路:
范围较大,直接运算会超时。
经过观察能够发现,[m, n]的按位与运算结果即为端点m,n的二进制表示中相同的前缀。

//实现a
int rangeBitwiseAnd(int m, int n) {
    int i;
    for(i = 0; m != n; i++)
        m >>= 1, n >>= 1;
    return m<<i;
}
//实现b
int rangeBitwiseAnd(int m, int n) {
    for(;n > m; n &= n-1);
    return n;
}

贴一份本身的其余解法,不算慢可是不够明了。

int rangeBitwiseAnd(int m, int n) {
    long long a = m,b = n;
    int r=m,i;
    for(i=0; m>>i;i++)
        (m>>i)&1 && ((a+(1<<i))>>i)<<i<=b&&(r&=~(1<<i));
    return r;
}

9. Repeated DNA Sequences

All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: “ACGAATTCCG”. When studying DNA, it is sometimes useful to identify repeated sequences within the DNA.

Write a function to find all the 10-letter-long sequences (substrings) that occur more than once in a DNA molecule.

For example,

Given s = “AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT”,
Return: [“AAAAACCCCC”, “CCCCCAAAAA”].

题目大意:
给出一个只包含ACGT的序列,求该序列中全部出现1次以上(最少两次)的长度为10的连续序列。

解题思路:
(正在更新)

//Runtime beats 100% ALL language solutions
//By BlackKitty

#include <string.h>
#define _(X) (X<'G'?X>'A':2|(X>'G'))
char l[1048576];
char** findRepeatedDnaSequences(char* s, int* returnSize) {
    char *p,**r;
    int n = 0, i, x, Z = (1 << 20) - 1, len;
    memset(l,0,sizeof(l));
    if ((len = strlen(s)) < 11) goto end;

    r = (char**)malloc(sizeof(char*)*len>>5);
    for (x = i = 0; i < 10; i++) x = (x << 2) | _(s[i]);
    for (p = s + 10; *(p-1);p++){
        if (!l[x]) l[x]++;
        else if (l[x] > 0){
            r[n] = (char*)malloc(sizeof(char)*11);
            for (i = 0; i < 10; i++) r[n][i] = i[p - 10];
            r[n++][10] = '\0';
            l[x] = -1;
        }
        x = ((x << 2) | _(*p))&Z;
    }
end:;
    *returnSize = n;
    return r;
}

(持续更新)