日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

《位运算技巧以及Leetcode的一些位运算题目》

發(fā)布時(shí)間:2023/12/1 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《位运算技巧以及Leetcode的一些位运算题目》 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

  • 技巧
  • 練習(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ù)字本身。神仙思路!

class Solution { public:int singleNumber(vector<int>& nums) {int result = 0;for(int num : nums)result = num ^ result;return result;} };

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

class Solution { public:vector<int> singleNumber(vector<int>& nums) {long res = 0;for(int i = 0; i < nums.size(); i++){res = res ^ nums[i];}//此時(shí)res = a ^ b;//找出1的位級(jí)表示中最低的那一位,代表著a與b在這一位是不一樣的,假設(shè)a在這一位為0,b在這一位為0res = res & (-res);int a = 0;int b = 0;for(int i = 0; i < nums.size(); i++){if((nums[i] & res) == 0) //不可能b,而且除了a其他符合要求的都是重復(fù)的a = nums[i] ^ a;else b = nums[i] ^ b;}return {a,b};} };

268. 丟失的數(shù)字

XOR原理:x ^ x = 0; 0 ^ y =y;
兩個(gè)相同的數(shù)字XOR之后為0,如果這個(gè)數(shù)字只出現(xiàn)了一次,那么XOR之后還是本身。這一題本質(zhì)上和上一題是一樣的。
一些細(xì)節(jié),看注釋

class Solution { public:int missingNumber(vector<int>& nums) {int n = nums.size();int result = n; //因?yàn)閒or循環(huán)中i不能為n,而我們必須遍歷[0,n],所以初值設(shè)置為nfor(int i = 0; i < n; i++) //遍歷nums數(shù)組,其丟失數(shù)在nums[] + [0..n]中只出現(xiàn)了一次{result = result ^ i ^ nums[i];}return result;} };

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的抑或即為所求。

class Solution { public:int findComplement(int n) {int tmp=0;int tmp_n = n;while(n){tmp = (tmp << 1) | 1;n >>= 1;}return tmp ^ tmp_n;} };

練習(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í)。

class Solution { public:bool isPowerOfFour(int n) {return ( n > 0 && (n & n-1) == 0 && (n & 0xaaaaaaaa) == 0);} };

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]

class Solution { public:vector<int> countBits(int num) {vector<int> dp(num+1,0);for(int i = 1; i <= num; i++){if((i & 1) == 1)dp[i] = dp[i-1] + 1;else dp[i] = dp[i>>1];}return dp;} };

一些補(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;
最終代碼:

vector<int> singleNumbers(vector<int>& nums) {int ret = 0;for(int n : nums)ret ^= n; // x^yint div = 1;while((ret & div) == 0)div <= 1;int x = 0, y = 0;for(int n : nums){if(div & n == 0)a ^= n;else b ^= n;}return vector<int> {x,y}; }

總結(jié)

以上是生活随笔為你收集整理的《位运算技巧以及Leetcode的一些位运算题目》的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。