LeetCode--Bit Manipulation

来源:互联网 发布:mac txt转码 编辑:程序博客网 时间:2024/06/08 04:42

关于位运算的总结,可参考这篇博客http://blog.csdn.net/black_ox/article/details/46411997

191. Number of 1 Bits(数字的二进制表示中1的数量)

Write a function that takes an unsigned integer and returns the number of ’1’ bits it has (also known as the Hamming weight).
For example, the 32-bit integer ’11’ has binary representation 00000000000000000000000000001011, so the function should return 3.

解析:

(1)方法一:n=n & (n-1)会使得n的二进制表示中最右边的1变成0。循环判断n!=0。有几个1就有几次循环。
(2)方法二:n & flag,flag初始为1,flag & n为1则代表n中某位为1,flag=flag<<1(右移),循环判断flag!=0。

C++代码实现:

class Solution {public:    int hammingWeight(uint32_t n) {        int count = 0;        /*        while(n) {            count++;            n = n & (n-1);      //去掉1个1        }*/        unsigned int flag = 1;        while(flag) {            if(n & flag)                count++;            flag <<= 1;        }        return count;    }};

136. Single Number

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

Note:

Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

解析:

(1)方法一:哈希表。用unordered_map记录数字的出现次数,然后遍历哈希表找到次数为1的数字。空间复杂度O(n)
(2)方法二:异或。数组中每个数字都出现两次除了一个数。我们知道,两个相同的数进行异或操作,结果为0。一个数和0异或,结果为其本省。因此,对数组中的数字进行异或操作,既可以得到结果。

C++代码实现:

class Solution {public:    int singleNumber(vector<int>& nums) {        /*        unordered_map<int,int> table;        for(auto a : nums)             table[a]++;        auto it = table.begin();        while(it!=table.end()) {            if(it->second==1)                return it->first;            it++;        }*/        int result = 0;        for(auto a : nums)            result = a ^ result;        return result;    }};

461. Hamming Distance

The Hamming distance between two integers is the number of positions at which the corresponding bits are different.
Given two integers x and y, calculate the Hamming distance.
Note:
0 ≤ x, y < 2^31.

Example:

Input: x = 1, y = 4
Output: 2
Explanation:
1 (0 0 0 1)
4 (0 1 0 0)
The above arrows point to positions where the corresponding bits are different.

解析:

海明距离指的是两个数字的32位二进制表示中,对应位置 位不同的数量。解法是,先对两个数字进行异或操作,num=x^y,然后判断num二进制表示中1的数量。

C++代码实现:

class Solution {public:    int hammingDistance(int x, int y) {        int num = x ^ y;        int count = 0;        unsigned int flag = 1;        while(flag) {            if(num&flag)                count++;            flag<<=1;        }        return count;    }};

169. Majority Element

Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.
You may assume that the array is non-empty and the majority element always exist in the array.

解析:

方法比较多。比如排序、哈希表、位操作等。《编程之美》上也提到了两种解法。下面介绍其中一种O(n)的算法。用times记录相同数字出现次数,用prev记录遍历到的数字。当遍历到下一个数字时,如果下一个数字和prev相同,则次数加1;如果不同,则减1。如果次数为0,需要设置prev为该数并且重新设置times为1。由于某个数字出现次数超过一半,那么该数字必是最后一次把times设为1时对应的数字prev。

C++代码实现:

class Solution {public:    int majorityElement(vector<int>& nums) {        int prev = nums[0];        int times = 1;      //记录数字出现次数        for(int i=1; i<nums.size(); ++i) {            if(times==0) {              //此时前面两个数字不同,times重新计数                prev = nums[i];                times = 1;            }else if(prev == nums[i])   //如果本次数字和上次数字相同,则times+1                times++;            else                //如果本次数字和上次数字不同,则times-1                times--;        }        return prev;    }};

405. Convert a Number to Hexadecimal

Given an integer, write an algorithm to convert it to hexadecimal. For negative integer, two’s complement method is used.

Note:

All letters in hexadecimal (a-f) must be in lowercase.
The hexadecimal string must not contain extra leading 0s. If the number is zero, it is represented by a single zero character ‘0’; otherwise, the first character in the hexadecimal string will not be the zero character.
The given number is guaranteed to fit within the range of a 32-bit signed integer.
You must not use any method provided by the library which converts/formats the number to hex directly.

解析:

求一个数的16进制表示,基本的做法是 num%16,num/=16,循环判断num!=0。其中num%16可以替换成num&(16-1),num/=16替换成num>>4。对于正数而言,无需预处理。对于负数,负数采用2的补数表示,但是其二进制表示是不变的。因此,无论是正负数都可以直接进行操作,处理的过程就是每次获取最低4位,将其对应的16进制表示添加到结果字符串的开头。关键的一点是,进行循环移位时,需要把数转为无符号数进行移位,因为右移操作符添加的值依赖于运算对象的类型,如果是无符号数,则添加0,否则添加符号位的副本或是0,根据具体环境而定。这里我们希望的是添加0,以便用于判断循环结束,所以进行了类型转换。

C++代码实现:

class Solution {public:    string toHex(int num) {        if(num==0)            return "0";        char dict[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};        string result;        while(num) {            result = dict[num & 0xf] + result; //num%16等价于 num & (16-1)            num = (unsigned)num>>4;                  }        return result;    }};

190. 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).
Follow up:
If this function is called many times, how would you optimize it?

解析:

将一个数n的二进制进行反转,然后求反转后的数字。只需要取出n的第k位 a,将a左移31-k位,即将第k位反转到了第31-k位。

C++代码实现:

class Solution {public:    uint32_t reverseBits(uint32_t n) {        uint32_t result = 0;        for(int i=0; i<32; i++) {            result += (n&1)<<(31-i);//取第i位            n>>=1;        }        return result;    }};

476. Number Complement

Given a positive integer, output its complement number. The complement strategy is to flip the bits of its binary representation.

Note:

The given integer is guaranteed to fit within the range of a 32-bit signed integer.
You could assume no leading zero bit in the integer’s binary representation.

C++代码实现:

class Solution {public:    int findComplement(int num) {        int result = 0;        int k = 0;        while(num) {            result += (1-(num&1))<<k;            num>>=1;            k++;        }        return result;    }};

231. Power of Two(判断一个数是否是2的幂)

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

解析:

如果一个数是2的幂,即n=2^k,则其具有这样的特性:n & (n-1)==0

C++代码实现:

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

342. Power of Four

Given an integer (signed 32 bits), write a function to check whether it is a power of 4.

Example:

Given num = 16, return true. Given num = 5, return false.
Follow up: Could you solve it without loops/recursion?

解析:

一个数是4的幂,则其必然是2的幂。因此,先判断n是否是2的幂,即n&(n-1)==0表示2的幂。然后,再判断n是否为4的幂。当一个数为4的幂时,其特点是,1只出现在偶数位(假设从0开始),比如1=0000 0001;4=0000 0100;16=0001 0000;64=0100 0000;由此,构造一个奇数位置全为0、偶数位全为1的数0x55555555,判断n & 0x55555555 ==n,也表示其为4的幂。(判断是2的幂的前提下)构造一个奇数位置全为1、偶数位全为0的数0xaaaaaaaa,如果n&0xaaaaaaaa==0,则表示其为4的幂。

C++代码实现:

class Solution {public:    bool isPowerOfFour(int num) {        if(num<=0)            return false;        if((num & (num-1))==0 && (num & 0x55555555)==num)          //if((num & (num-1))==0 && (num & 0xaaaaaaaa)==0)            return true;        return false;    }};

371. Sum of Two Integers

Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -.

Example:

Given a = 1 and b = 2, return 3.

解析:

a+b=(a|b)+(a&b);
a-b=(a|~b)-(~x&y)

C++代码实现:

class Solution {public:    int getSum(int a, int b) {        return (a|b)+(a&b);    }};

268. 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.

Note:

Your algorithm should run in linear runtime complexity. Could you implement it using only constant extra space complexity?

解析:

(1)方法一:等差数组。total=n*(n+1)/2,然后将数组中所有数字相加成sum,数组中缺失的数为total-sum。
(2)方法二:二分搜索
(3)方法三:异或法。原本数组中的数应为[0,1,2,3,4,5,…],其对应的下标也为[0,1,2,3,4,5,..],则 i^num[i]==0。现在数组中缺少某个数k,则从数k+1开始,其下标往前移了一个位置,于是可以使用异或操作,找出缺失的数,即 k=n ^ (i^num[i])^…。

C++代码实现:
方法一

class Solution {public:    int missingNumber(vector<int>& nums) {        int n = nums.size();        int total = (n*(n+1))/2;        for(auto a:nums)            total -= a;        return total;    }};

方法三:

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

389. Find the Difference

Given two strings s and t which consist of only lowercase letters.
String t is generated by random shuffling string s and then add one more letter at a random position.
Find the letter that was added in t.

Example:

Input:
s = “abcd”
t = “abcde”
Output:
e
Explanation:
‘e’ is the letter that was added.

解析:

(1)方法一:哈希表。
(2)方法二:异或操作。将s和t中所有字母进行异或操作,最后的结果即为t中多出来的字符。

C++代码实现:
方法二

class Solution {public:    char findTheDifference(string s, string t) {        int result = 0;        for(auto c : s)            result ^= c;        for(auto c : t)            result ^= c;        return result;    }};

方法一

class Solution {public:    char findTheDifference(string s, string t) {        unordered_map<char,int> dict;        for(auto c : s)            dict[c]++;        for(auto c : t) {            if(dict.count(c)==0)                return c;            else {                dict[c]--;                if(dict[c]==0)                    dict.erase(c);            }        }        return 0;    }};

78. Subsets(数组的子集)

Given a set of distinct integers, nums, return all possible subsets.
Note: The solution set must not contain duplicate subsets.

For example,

If nums = [1,2,3], a solution is:
[ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]

解析:

用0和1代表某个数字是否放入集合中,比如101代表把1和3放入集合。集合的总数为2^n,可以用0~2^n-1表示。

C++代码实现:

class Solution {public:    vector<vector<int>> subsets(vector<int>& nums) {        sort(nums.begin(),nums.end());        int subset_count = pow(2,nums.size());        vector<vector<int>> subset(subset_count,vector<int>());        for(int i=0; i<nums.size(); ++i) {            for(int j=0; j<subset_count; ++j) {                if( (j>>i) & 1 ) //判断j的第i为是否为1,为1则放入j集合中。                   subset[j].push_back(nums[i]);             }        }        return subset;    }};

318. Maximum Product of Word Lengths

Given a string array words, find the maximum value of length(word[i]) * length(word[j]) where the two words do not share common letters. You may assume that each word will contain only lower case letters. If no such two words exist, return 0.

Example 1:

Given [“abcw”, “baz”, “foo”, “bar”, “xtfn”, “abcdef”]
Return 16
The two words can be “abcw”, “xtfn”.

Example 2:

Given [“a”, “ab”, “abc”, “d”, “cd”, “bcd”, “abcd”]
Return 4
The two words can be “ab”, “cd”.

Example 3:

Given [“a”, “aa”, “aaa”, “aaaa”]
Return 0
No such pair of words.

解析:

(1)方法一:对于每个Word[i],用unordered_set记录其中不同的字母,然后逐个对i后的每个单词进行比对,如果两个单词没有重复的字母,则记录word[i].len*word[j].len。该方法的时间复杂度为O(n^2)。
(2)方法二:上一方法中使用unordered_set记录单词不同的字母,本方法中用vector < int >dict,使用按位或的方式记录。即dict[i] |= 1<<(c-‘a’),比如abdef的结果为00000000000000000000000000111011。如果两个单词有重复的字母,则dict[i]&dict[j]结果不为0。如果两个单词的dict[i]&dict[j]结果为0,意味着两者不存在重复单词。

C++代码实现:
方法二

class Solution {public:    int maxProduct(vector<string>& words) {        int result = 0;        vector<int> dict(words.size(),0);        for(int i=0; i<words.size(); i++) {            for(char c : words[i])                dict[i] |= 1<<(c-'a');      //用 按位或的方式 记录每个单词中的不同字母        }        for(int i=0; i<words.size(); i++) {            for(int j=i+1; j<words.size(); j++) {                if( (dict[i] & dict[j])==0 && result < words[i].size()*words[j].size())                    result = words[i].size()*words[j].size();            }        }        return result;    }};

方法一

class Solution {public:    int maxProduct(vector<string>& words) {        int result = 0;        bool flag = true;        for(int i=0; i<words.size(); i++) {            unordered_set<char> dict(words[i].begin(),words[i].end());            for(int j=i+1; j<words.size(); j++) {                for(char c : words[j]) {                    if(dict.count(c)){                        flag = false;                        break;                    }                }                if(flag)                    result = result >= words[i].size()*words[j].size() ? result : words[i].size()*words[j].size();                flag = true;            }        }        return result;    }};

260. 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].

Note:

The order of the result is not important. So in the above example, [5, 3] is also correct.
Your algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity?

解析:

(1)方法一:哈希表。用unordered_map < int, int >记录数组中每个数字的出现次数,然后遍历哈希表,出现次数为1的数即为答案。
(2)方法二:异或法。不同于数组中只有1个数字出现1次的解法。该题中需要进行两次异或操作。第一次异或操作,先求得要找的两个数A和B的异或结果,即mask=A^B。然后从mask中取最右边的1,可以使用mask &= -mask。用mask对数每个数字进行 &操作,将数组分成两部分,A和B必然会出现在不同部分,然后对这两部分进行第二次的异或操作,结果即为答案。

C++代码实现:
方法二

class Solution {public:    vector<int> singleNumber(vector<int>& nums) {        int mask = 0;        //phase 1        for(int n : nums)            mask ^= n;      //得到异或结果        mask &= -mask;      //得到mask的二进制表示中最右边的1        int first = 0;        int second = 0;        //phase 2        for(int n : nums) {            if(n & mask)        //用mask将数组分成两部分,然后分别从两边找出现一次的数字                first ^= n;            else                second ^= n;        }        vector<int> result = {first,second};        return result;    }};

393. UTF-8 Validation

A character in UTF8 can be from 1 to 4 bytes long, subjected to the following rules:
For 1-byte character, the first bit is a 0, followed by its unicode code.
For n-bytes character, the first n-bits are all one’s, the n+1 bit is 0, followed by n-1 bytes with most significant 2 bits being 10.

This is how the UTF-8 encoding would work:
Char. number range | UTF-8 octet sequence
(hexadecimal) | (binary)
——————–+———————————————
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
Given an array of integers representing the data, return whether it is a valid utf-8 encoding.

Note:

The input is an array of integers. Only the least significant 8 bits of each integer is used to store the data. This means each integer represents only 1 byte of data.

Example 1:

data = [197, 130, 1], which represents the octet sequence: 11000101 10000010 00000001.
Return true.
It is a valid utf-8 encoding for a 2-bytes character followed by a 1-byte character.

Example 2:

data = [235, 140, 4], which represented the octet sequence: 11101011 10001100 00000100.
Return false.
The first 3 bits are all one’s and the 4th bit is 0 means it is a 3-bytes character.
The next byte is a continuation byte which starts with 10 and that’s correct.
But the second continuation byte does not start with 10, so it is invalid.

解析:

一个UTF8字符其字节长度为1-4bytes,并且遵循以下规则:
(1)对于1-bytes的字符,第1位为0,后面7位紧跟Unicode代码,比如0xxxxxxx;
(2)对于n-bytes的字符,前n位为1,n+1位为0,然后紧跟的n-1 个字符,这些字符开头为10,比如案例2。
由上面可知,
(1)字符不可能大于255;
(2)大于240,即11110xxx,代表4bytes;大于224,即1110xxxx,代表3bytes;大于192,即110xxxxx,代表2bytes;小于128,即0xxxxxxx,代表1bytes。
详情见代码注释。

C++代码实现:
第二次写的代码:

class Solution {public:    bool validUtf8(vector<int>& data) {        int count = 0;        for(int i=0; i<data.size(); i++) {            count = 0;            if(data[i] > 255)                return false;            else if( (data[i] & 248) == 240 )  //11110xxx -> [240,247],代表4bytes                count = 4;            else if( (data[i] & 240) == 224)   //1110xxxx -> [224,239],代表3bytes                count = 3;            else if( (data[i] & 224) == 192)   //110xxxxx -> [192,223],代表2bytes                count = 2;            else if( (data[i] & 128) == 0)     //0xxxxxxx -> [0,127],代表1bytes                count = 1;            else                return false;            for(int j=1; j<count; j++){  //判断后面count-1个字符                if(i+j>=data.size())                    return false;                if( (data[i+j] & 192) != 128 )    //判断是否以10开头,[128,191]                    return false;            }            i += count-1;        }        return true;    }};

第一次写的代码:

class Solution {public:    bool validUtf8(vector<int>& data) {        int count = 0;        int i = 0;        while(i<data.size()) {            count = getCount(data[i]);            //cout<<data[i]<<" : "<<count<<endl;            if(count==1 || count>4)                return false;            if(!validFollow(data,i+1,count-1))                return false;            if(count==0)                i++;            else                i += count;        }        return true;    }private:    int getCount(int num) {  //判断n-bytes character        int count = 0;        int k = 7;        while( k>=0 && (num>>k)&1 ) {            count++;            k--;        }        return count;    }    bool validFollow(vector<int>& data,int start,int count) {   //验证followed n-1 bytes是否是10开头        if(count<=0)            return true;        if(start >= data.size() || start+count > data.size())            return false;        for(int i=start; i<(start+count); ++i) {            if(!startWithOneZero(data[i]))                return false;        }        return true;    }    bool startWithOneZero(int num) {        //cout<<num<<" : "<<((num>>7) & 1) << ((num>>6) & 1) <<endl;        if( ((num>>7) & 1) && !((num>>6) & 1))            return true;        return false;    }};
原创粉丝点击