wordpress配置教程網(wǎng)站優(yōu)化快速排名軟件
目錄
- 一,常見位運(yùn)算操作總結(jié)
- 二,算法原理和代碼實(shí)現(xiàn)
- 191.位1的個(gè)數(shù)
- 338.比特位計(jì)數(shù)
- 461.漢明距離
- 面試題01.01.判斷字符是否唯一
- 268.丟失的數(shù)字
- 371.兩整數(shù)之和
- 136.只出現(xiàn)一次的數(shù)字
- 137.只出現(xiàn)一次的數(shù)字II
- 260.只出現(xiàn)一次的數(shù)據(jù)III
- 面試題17.19.消失的兩個(gè)數(shù)字
- 三,算法總結(jié)
一,常見位運(yùn)算操作總結(jié)
1. 基礎(chǔ)位運(yùn)算符
注意:參與位運(yùn)算的對(duì)象只能是整型數(shù)據(jù)(int, unsigned, char),不能為實(shí)型。
上面六種基礎(chǔ)位運(yùn)算是本篇文章重點(diǎn)涉及的,要想詳細(xì)了解它們的含義和運(yùn)算規(guī)律,請(qǐng)點(diǎn)擊文章:【移位操作符,位操作符運(yùn)算規(guī)則詳解】
2. 位運(yùn)算符的優(yōu)先級(jí)
只要記住一句話:表格不用死記,能加括號(hào)就加括號(hào)。
3. 給定一個(gè)數(shù) n ,判斷他的二進(jìn)制表示的第 x 位是 0 還是 1?
(n >> x) & 1
4. 將一個(gè)數(shù) n 的二進(jìn)制表示的第 x 位修改成 1
n |= (1 << x)
5. 將一個(gè)數(shù) n 的二進(jìn)制表示的第 x 位修改成 0
n &= (~(1 << x))
6. 位圖思想
位圖的本質(zhì)是哈希表,是一個(gè)用二進(jìn)制比特位表示數(shù)據(jù)是否存在的數(shù)據(jù)結(jié)構(gòu)。
想詳細(xì)了解什么是位圖以及位圖的使用,請(qǐng)點(diǎn)擊文章:【哈希的應(yīng)用 – 位圖&布隆過濾器】
7. 提取一個(gè)數(shù)(n)二進(jìn)制表示中最右側(cè)的 1
n & -n
8. 干掉一個(gè)數(shù)(n)二進(jìn)制表示中最右側(cè)的 1
n & (n - 1)
9. 異或(^)運(yùn)算的運(yùn)算律
二,算法原理和代碼實(shí)現(xiàn)
191.位1的個(gè)數(shù)
算法原理:
根據(jù)上面總結(jié)的位運(yùn)算的操作,這道題有兩種解法。
代碼實(shí)現(xiàn)1:
根據(jù)上面的第三點(diǎn),可以判斷 n 的二進(jìn)制里的每一位是否是1,如果是,計(jì)數(shù)器++。
class Solution
{
public:int hammingWeight(int n){int count = 0;for (int i = 0; i < 32; i++){if ((n >> i) & 1) count++;}return count;}
};
代碼實(shí)現(xiàn)2:
根據(jù)上面的第8點(diǎn),每次都干掉數(shù) n 的最右側(cè)的1,統(tǒng)計(jì)執(zhí)行的次數(shù)即可。
class Solution {
public:int hammingWeight(int n) {int count = 0;while (n){n &= (n - 1);count++;}return count;}
};
338.比特位計(jì)數(shù)
算法原理:
這道題就是上一題的進(jìn)階題,算法原理同上,加一個(gè)循環(huán)遍歷從0到n的數(shù)字,分別計(jì)算出每個(gè)數(shù)字的二進(jìn)制中1的個(gè)數(shù),存入數(shù)組中即可。
代碼實(shí)現(xiàn):
class Solution
{
public:vector<int> countBits(int n) {vector<int> ret;for(int i = 0; i <= n; i++){int tmp = i;unsigned int count = 0;while(tmp){tmp &= (tmp-1);count++;}ret.push_back(count);}return ret;}
};
461.漢明距離
算法原理:
根據(jù)上面的操作三,判斷這兩個(gè)數(shù)的每一位是否相等,如果不相等,計(jì)數(shù)器++ 即可。
代碼實(shí)現(xiàn):
class Solution
{
public:int hammingDistance(int x, int y) {int i = 0;int count = 0;for(; i < 32; i++)if(((x >> i) & 1) != ((y >> i) & 1)) count++;return count;}
};
面試題01.01.判斷字符是否唯一
算法原理:
這道題比較簡(jiǎn)單,有多種解法:一是使用位圖思想,二是使用哈希表,三是用數(shù)組模擬哈希。
這里介紹位圖思想。
用一個(gè) int 變量的32個(gè)比特位(實(shí)際上只使用26個(gè))來標(biāo)記這個(gè)字符在或不在,0 表示不在,1 表示在。
所以先要判斷二進(jìn)制中的第 n 位是 1 還是 0,如果是 0,就修改成 1,如果已經(jīng)是 1 了,說明這個(gè)字符就已經(jīng)存在了,返回false。
這里還有一個(gè)小的優(yōu)化點(diǎn):
由鴿巢原理(抽屜原理)可知,當(dāng)字符串的長(zhǎng)度大于26個(gè)時(shí),一定會(huì)出現(xiàn)重復(fù)字符。
代碼實(shí)現(xiàn)1:使用位圖思想
class Solution
{
public:bool isUnique(string astr){if(astr.size() > 26) return false;int bitMap = 0;for (auto ch : astr){int i = ch - 'a'; // 移動(dòng)的位數(shù)// 字符不存在,映射位置的比特位修改成1if (((bitMap >> i) & 1) == 0) bitMap |= (1 << i);else return false;}return true;}
};
代碼實(shí)現(xiàn)2:使用哈希表
時(shí)間復(fù)雜度:O(N)
空間復(fù)雜度:O(N)
class Solution
{
public:bool isUnique(string astr){if(astr.size() > 26) return false;unordered_map<char, int> hash;for (auto ch : astr){// 判斷是否存在if (hash.count(ch) == 0) hash[ch]++;else return false;}return true;}
};
代碼實(shí)現(xiàn)3:用數(shù)組模擬哈希
class Solution
{
public:bool isUnique(string astr){if(astr.size() > 26) return false;int hash[26] = { 0 };for (auto ch : astr){if (hash[ch - 'a'] == 0) hash[ch - 'a']++;else return false;}return true;}
};
268.丟失的數(shù)字
算法原理:
這道題其實(shí)和 [二分查找] 系列中的最后一題是一模一樣的,題目簡(jiǎn)單,解法多種。
這里介紹使用位運(yùn)算。
使用異或運(yùn)算的規(guī)律:
a ^ 0 = a
a ^ a = 0
a ^ b ^ c = a ^ (b ^ c)
可以先把完整的 [0, n] 共 n + 1 個(gè)數(shù)進(jìn)行異或,再把這個(gè)異或結(jié)果異或上題目所給的數(shù)據(jù),相同數(shù)異或變成0,最后剩下的那個(gè)就是缺失的數(shù)字。
代碼實(shí)現(xiàn):
class Solution
{
public:int missingNumber(vector<int>& nums) {int ret = 0;for(int i = 0; i <= nums.size(); i++)ret ^= i;for(auto x : nums)ret ^= x;return ret;}
};
如果想要了解其他解法,請(qǐng)點(diǎn)擊文章:【二分查找】里的最后一題 [LCR173.點(diǎn)名]。
371.兩整數(shù)之和
算法原理:
這道題使用異或運(yùn)算 – 無進(jìn)位相加。
先算出無進(jìn)位相加的結(jié)果,再算出進(jìn)位,再把兩者相加,但是不能使用加法,要重復(fù)執(zhí)行上面兩個(gè)操作,直到進(jìn)位為 0 為止。
代碼實(shí)現(xiàn):
class Solution
{
public:int getSum(int a, int b) {int tmp = a ^ b; // 無進(jìn)位相加的結(jié)果int res = (a & b) << 1; // 算出進(jìn)位// 當(dāng)進(jìn)位不為0時(shí),重復(fù)上面操作while(res){a = tmp;b = res;tmp = a ^ b;res = (a & b) << 1;}return tmp;}
};
136.只出現(xiàn)一次的數(shù)字
算法原理:
這道題很簡(jiǎn)單,就是對(duì)異或運(yùn)算律(a ^ a = 0)的簡(jiǎn)單使用。
代碼實(shí)現(xiàn):
class Solution
{
public:int singleNumber(vector<int>& nums) {int ret = 0;for(auto x : nums)ret ^= x;return ret;}
};
137.只出現(xiàn)一次的數(shù)字II
算法原理:
把所有數(shù)據(jù)的第 i 個(gè)二進(jìn)制位相加,和會(huì)出現(xiàn)下面4種情況:
用相加的和取模3(%3),如果是三個(gè)相同的數(shù),它們的第 i 個(gè)二進(jìn)制位相加結(jié)果模3為 0,如果等于 1,說明這個(gè)二進(jìn)制位是那個(gè)只出現(xiàn)一次的數(shù)的,就把它映射到另一個(gè) int 變量的對(duì)應(yīng)的二進(jìn)制位上。
代碼實(shí)現(xiàn):
class Solution
{
public:int singleNumber(vector<int>& nums) {int ret = 0;for(int i = 0; i < 32; i++){int sum = 0;for(auto x : nums)sum += ((x >> i) & 1); // 把所有數(shù)字的第i個(gè)二進(jìn)制位相加// 如果等于1,說明是出現(xiàn)一次的,把1映射到相應(yīng)的二進(jìn)制位if(sum % 3 != 0) ret |= (1 << i); }return ret;}
};
260.只出現(xiàn)一次的數(shù)據(jù)III
算法原理:
其實(shí)根據(jù) [136.只出現(xiàn)一次的數(shù)字] 對(duì)這道題是有思路的,就是相同的數(shù)異或在一起就變成0了,關(guān)鍵就是如何把相同的數(shù)放到一組?
代碼實(shí)現(xiàn):
class Solution
{
public:vector<int> singleNumber(vector<int>& nums) {int tmp = 0;// 把所有數(shù)據(jù)異或在一起for(auto x : nums)tmp ^= x;// 找出tmp中,比特位上為1的位置int i = 0;for(; i < 32; i++)if((tmp >> i) & 1) break;// 根據(jù)i的位置把數(shù)據(jù)分成兩類,分別異或int a = 0, b = 0;for(auto x : nums)if((x >> i) & 1) a ^= x;else b ^= x;return {a, b};}
};
面試題17.19.消失的兩個(gè)數(shù)字
算法原理:
這道題本質(zhì)上是 [268.消失的數(shù)字] 和 [260.只出現(xiàn)一次的數(shù)字III] 的結(jié)合題。
代碼實(shí)現(xiàn):
class Solution
{
public:vector<int> missingTwo(vector<int>& nums) {int tmp = 0;// 把所屬異或在一起for(auto x : nums) tmp ^= x;for(int k = 1; k <= nums.size()+2; k++) tmp ^= k;// 找到tmp中,比特位上為1的那一位int i = 0;for(; i < 32; i++)if((tmp >> i) & 1) break;// 根據(jù)第i位的不同,把所有數(shù)據(jù)分成兩類int a = 0, b = 0;for(auto x : nums)if((x >> i) & 1) a ^= x;else b ^= x;for(int j = 1 ; j <= nums.size()+2; j++)if((j >> i) & 1) a ^= j;else b ^= j;return {a, b};}
};
三,算法總結(jié)
熟練使用位運(yùn)算的操作即可。