《位运算技巧以及Leetcode的一些位运算题目》
目錄
- 技巧
- 練習(xí)位運(yùn)算
- [461. 漢明距離](https://leetcode-cn.com/problems/hamming-distance/)
- [190. 顛倒二進(jìn)制位](https://leetcode-cn.com/problems/reverse-bits/)
- [136. 只出現(xiàn)一次的數(shù)字](https://leetcode-cn.com/problems/single-number/)
- [260. 只出現(xiàn)一次的數(shù)字 III](https://leetcode-cn.com/problems/single-number-iii/)
- [268. 丟失的數(shù)字](https://leetcode-cn.com/problems/missing-number/)
- [693. 交替位二進(jìn)制數(shù)](https://leetcode-cn.com/problems/binary-number-with-alternating-bits/)
- [476. 數(shù)字的補(bǔ)數(shù)](https://leetcode-cn.com/problems/number-complement/)
- 練習(xí)二進(jìn)制思想
- [342. 4的冪](https://leetcode-cn.com/problems/power-of-four/)
- [318. 最大單詞長(zhǎng)度乘積](https://leetcode-cn.com/problems/maximum-product-of-word-lengths/)
- [338. 比特位計(jì)數(shù)](https://leetcode-cn.com/problems/counting-bits/)
- 一些補(bǔ)充
- 劍指 Offer 56 - I. 數(shù)組中數(shù)字出現(xiàn)的次數(shù)
技巧
位運(yùn)算的一些基礎(chǔ)技巧:
x ^ 0... = xx ^ 1... = ~xx ^ x = 0x & 0... = 0x & 1... = xx & x = xx | 0... = xx | 1... = 1...x | x = x進(jìn)階技巧:
n & (n-1) 可以去除n的位級(jí)表示中最低的一位: 如 n = 11110100 , n - 1 = 11110011 n & (n-1) = 11110000 n & (-n) 可以得到n的位級(jí)表示中最低的那一位: 如 n = 11110100 , 取負(fù):-n = 00001100 n & (-n) = 00000100練習(xí)位運(yùn)算
461. 漢明距離
先異或運(yùn)算,然后統(tǒng)計(jì)1個(gè)數(shù):
class Solution { public:int hammingDistance(int x, int y) {int XOR_result = x ^ y;int result = 0;while(XOR_result != 0){result += (XOR_result & 1);XOR_result = XOR_result >> 1;}return result;} };190. 顛倒二進(jìn)制位
result不斷左移,最低位加上n的最低位,n不斷右移。
class Solution { public:uint32_t reverseBits(uint32_t n) {uint32_t result = 0;for(int i = 0; i < 32; i++){result = result << 1;result += n & 1;n = n >> 1;}return result;} };136. 只出現(xiàn)一次的數(shù)字
思路一:哈希先掃一遍,然后再掃一遍,找到second為1的it。
class Solution { public:int singleNumber(vector<int>& nums) {unordered_map<int,int> umap;int result = 0;for(int i = 0; i < nums.size(); i++){umap[nums[i]]++;}for(auto it : umap){if(it.second == 1) return it.first;}return 0;} };思路二:利用 x ∧ x = 0 和 x ∧ 0 = x 的特點(diǎn),將數(shù)組內(nèi)所有的數(shù)字進(jìn)行按位異或。出現(xiàn)兩次
的所有數(shù)字按位異或的結(jié)果是 0,0 與出現(xiàn)一次的數(shù)字異或可以得到這個(gè)數(shù)字本身。神仙思路!
260. 只出現(xiàn)一次的數(shù)字 III
這次是有兩個(gè)不同的元素,那么用位運(yùn)算如何做呢?
覺得這個(gè)題解寫的很好,淺顯易懂。
某題解
編程時(shí)注意一下細(xì)節(jié):
1、&的優(yōu)先級(jí)比==低,所以需要加括號(hào)
2、用int作為res會(huì)報(bào)錯(cuò),需要用long
268. 丟失的數(shù)字
XOR原理:x ^ x = 0; 0 ^ y =y;
兩個(gè)相同的數(shù)字XOR之后為0,如果這個(gè)數(shù)字只出現(xiàn)了一次,那么XOR之后還是本身。這一題本質(zhì)上和上一題是一樣的。
一些細(xì)節(jié),看注釋
693. 交替位二進(jìn)制數(shù)
class Solution { public:bool hasAlternatingBits(int n) {int prev_tail = n & 1;while(n){int now_tail = (n >> 1) & 1;if(now_tail == prev_tail) return false;prev_tail = now_tail;n = n >> 1;}return true;} };476. 數(shù)字的補(bǔ)數(shù)
思路一:一個(gè)一個(gè)來,注意倒序。
class Solution { public:int findComplement(int n) {int result = 0;vector<int> res;while(n){res.emplace_back(!(n & 1));n = n >> 1;}for(int i = res.size() - 1; i >=0; i--){result = (result << 1) | res[i];}return result;} };當(dāng)然也可以使用棧來做,思路一樣的:
class Solution { public:int findComplement(int n) {int result = 0;stack<int> res;while(n){res.push(!(n&1));n >>= 1;}while(!res.empty()){result = (result << 1) | res.top();res.pop();}return result;} };思路二:使用異或
舉例:
5的二進(jìn)制是:0101,7的二進(jìn)制是: 0111,它們的抑或?yàn)?#xff1a;0010,去掉前導(dǎo)零位即為取反。
再來一個(gè)例子,假設(shè)a為1110 0101,b為1111 1111,a^b = 0001 1010是a的取反。也就是說二進(jìn)制位數(shù)與num相同,且全為1的數(shù)tmp與num的抑或即為所求。
練習(xí)二進(jìn)制思想
342. 4的冪
先考慮2的次方:
如果n為2的整數(shù)次方,那么它的二進(jìn)制一定是0...1...0的形式;那么n-1的二進(jìn)制應(yīng)該是0..011...1的形勢(shì)。這兩個(gè)數(shù)按位求與的結(jié)果一定為0。
如果n為4的整數(shù)次方,它一定為2的偶數(shù)冪。所以4的冪與二進(jìn)制數(shù)(1010101010…10)相與會(huì)得到0.
int 為32位,每4位1010對(duì)應(yīng)16進(jìn)制a,所以應(yīng)該為0xaaaaaaaa;
注意&與==的優(yōu)先級(jí)。
318. 最大單詞長(zhǎng)度乘積
怎樣快速判斷兩個(gè)字母串是否含有重復(fù)數(shù)字呢?可以為每個(gè)字母串建立一個(gè)長(zhǎng)度為26的二進(jìn)制數(shù)字,每個(gè)位置表示是否存在該字母。如果兩個(gè)字母串含有重復(fù)數(shù)字,那它們的二進(jìn)制表示的按位與不為0。同時(shí),我們可以建立一個(gè)哈希表來存儲(chǔ)字母串(在數(shù)組的位置)到二進(jìn)制數(shù)字的映射關(guān)系,方便查找調(diào)用。
class Solution { public:int maxProduct(vector<string>& words) {unordered_map<int,int> hashmap; //使用哈希表來存儲(chǔ)(位掩碼 -> 單詞長(zhǎng)度)int ans = 0;for(auto word : words) //遍歷每個(gè)string{int mask = 0; //位掩碼int size = word.size(); //單詞長(zhǎng)度for(auto c : word) //encode位掩碼mask = mask | (1 << (c-'a'));hashmap[mask] = max(hashmap[mask],size);//如果掩碼相同,存儲(chǔ)更長(zhǎng)的字符串(說明有些字符重復(fù))//對(duì)比當(dāng)前單詞與之前的所有單詞,無重復(fù)字符,且長(zhǎng)度乘積大于ans則更新ansfor(auto it : hashmap){if((mask & it.first)== 0) //如果無重復(fù)字符{ans = max(ans,size*it.second);}}}return ans;} };338. 比特位計(jì)數(shù)
利用dp+位運(yùn)算。
定義一個(gè)數(shù)組dp,dp[i]表示數(shù)字i的二進(jìn)制含有1的個(gè)數(shù)。
對(duì)于第i個(gè)數(shù)字,如果它二進(jìn)制的最后一位為1,那么它含有1的個(gè)數(shù)則為dp[i] = dp[i-1]+1;
如果它二進(jìn)制的最后一位為0,那么它含有1的個(gè)數(shù)和其右移結(jié)果相同,即dp[i] = dp[i>>1]
一些補(bǔ)充
2021.7.4
劍指 Offer 56 - I. 數(shù)組中數(shù)字出現(xiàn)的次數(shù)
一個(gè)整型數(shù)組 nums 里除兩個(gè)數(shù)字之外,其他數(shù)字都出現(xiàn)了兩次。請(qǐng)寫程序找出這兩個(gè)只出現(xiàn)一次的數(shù)字。要求時(shí)間復(fù)雜度是O(n),空間復(fù)雜度是O(1)。
示例 1: 輸入:nums = [4,1,4,6] 輸出:[1,6] 或 [6,1] 示例 2: 輸入:nums = [1,2,10,4,1,4,3,3] 輸出:[2,10] 或 [10,2] 限制: 2 <= nums.length <= 10000兩個(gè)只出現(xiàn)依次的數(shù)字位x,y
x和y二進(jìn)制至少有一位不同,根據(jù)此位可以將nums劃分成分別包含x和y的兩個(gè)子數(shù)組。
分別對(duì)兩個(gè)子數(shù)組遍歷執(zhí)行異或操作,可以得到兩個(gè)只出現(xiàn)一次的數(shù)字x,y。
1、遍歷nums數(shù)組執(zhí)行異或,得到結(jié)果 x^y
2、x^y某二進(jìn)制位為1,則x和y的此二進(jìn)制位一定不同。
初始化一個(gè)輔助變量m = 1,從右向左循環(huán)判斷,可以得到x^y的首位1,記錄在m中。
3、拆分nums為兩個(gè)子數(shù)組
4、分別遍歷兩個(gè)子數(shù)組執(zhí)行異或
for(num : nums)
if(num & m == 1) x ^= num;
else y ^= num;
return x,y;
最終代碼:
總結(jié)
以上是生活随笔為你收集整理的《位运算技巧以及Leetcode的一些位运算题目》的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信阳治疗子宫内膜异位症最好的医院推荐
- 下一篇: 《DBNotes:single_tabl