位运算在一类数组题中的用法 只出现一次的数字I
文章目錄
- 前言
- 復習
- 一:只出現一次的數字I
- 二:只出現一次的數字II
- 二:只出現一次的數字III
前言
LeetCode上有幾道題特別相似,分別是leetcode 136只出現一次的數(簡單),137只出現一次的數Ⅱ(中等),260只出現一次的數Ⅲ。
這幾道題當然有很多中解法,但是其中有一種解法特別獨特,也是很多人無法想到的,那么就是利用位運算,說起位運算,其實很多人都忘記了,只是知道怎么回事,但是不知道它具體有什么用處。讀完本文,你就能感覺到它的神奇之處了
復習
既然需要使用位運算,那么在這里我們就先復習一下吧
左移和右移
一:只出現一次的數字I
題目
這道題需要借助到異或運算符對于參與運算的兩個對象,如果對應二進制位不同結果是1,否則就是0。主要使用的性質有**:0異或任何數等于任何數,任何數異或自己都等于0,異或運算滿足結合律和交換律**
所以對于上面的數組【4,1,2,1,2】,我們可以4 ^ 1 ^ 2 ^ 1 ^ 2 ,也就是4 ^ 1 ^ 1 ^ 2 ^ 2,所以4 ^ (1 ^ 1) ^ (2 ^ 2),所以4 ^ 0 ^ 0,所以結果就是4
class Solution { public:int singleNumber(vector<int>& nums) {int value=0;for(auto e : nums){value=value^e;}return value;} };二:只出現一次的數字II
題目
對于這道題,有一種方法是自動機,但是比較難以理解,詳情可以看這篇文章的講解
但我們最常使用的還是直接用位運算
首先需要發現規律,將我們的數的二進制位每一位對應相加,然后對每一位的和進行取余
這里大家注意觀察最終取余的結果和目標值。之所以這樣做的原因是因為,如果其他書都出現了3次,只有目標數出現了1次,那么每一位為1的個數無非就是3的倍數或3的倍數+1,而3的倍數+1也就是我們要找的那個情況
代碼如下:
class Solution { public:int singleNumber(vector<int>& nums){int ret=0;for(int i=0;i<32;i++){int count=0;for(int j=0;j<nums.size();j++){if((nums[j]>>i & 1) == 1){count++;}}if(count%3!=0){ret=ret | 1 << i;}}return ret;}};第一個for循環用于控制數字的每一個二進制位,進入第一個for循環之后,定義一個count,用來保存此時各數字對應二進制位的和,然后第二個循環首先判斷該數字的這一二進制位是否是1,判斷時只需要讓這個數字右移由i控制的位數,讓判斷的位置跑到最低位,然后與1進行與運算,因為與運算是兩者“同時是1才能是1”,所以一旦結果不等于1,說明判斷的這一位就不是1,如果是1則count++,第二個for循環結束后,所有數字對應的二進制位加和就完畢了,接著根據之前的性質判斷,如果取余不等于0,說明count是3的倍數+1,是由于那個單獨出現的數字導致的,因此ret與1進行或運算,讓其最后一位變為1(這個1就是單獨出現的數字的某一二進制位),由于之前右移了i位,所以現在讓其左移i位,回正
二:只出現一次的數字III
這道題和第一題有點相似,但是它是有兩個單獨出現的數字,如果直接使用異或,那么得到結果就是拿兩個目標數的異或值,肯定是不行的
所以我們可以這樣做,將元素分為兩組,每組包含一個目標值,然后組內異或,那么每組的最終結果就是一個目標值
比如【a,b,a,b,c,d,e,f,e,f】進行分組后,組A為:【a,a,b,b,c】,組B為:【e,e,f,f,d】,組A得到c,組B得到d。
c和d不同,所以其異或的結果一定不是0,我們只研究其最右面那一位(其實任何一位都可以),也就是讓其異或結果變為0或1,接著以0或1作為標準,讓數組內的元素進行分組,比如說異或結果是1,我就這樣判斷:和1與運算的結果為1的分為1組,為0的分為另外一組,我不需要管它到底在哪一組,我只明白相同的數字肯定在一組
那么最后一點就是如何讓其異或結果變為0或1呢,假設異或結果是
temp,只需要temp & (-temp),因為負數等原數按位取反+1
總結
以上是生活随笔為你收集整理的位运算在一类数组题中的用法 只出现一次的数字I的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: windows环境下封装条件wait和s
- 下一篇: 思想实验(逻辑思维)解题