算法题:找出整数数组中两个只出现一次的数字
問(wèn)題:一個(gè)整數(shù)數(shù)組里除了兩個(gè)數(shù)字之外,其他的數(shù)字都出現(xiàn)了兩次。請(qǐng)寫(xiě)程序找出這兩個(gè)只出現(xiàn)一次的數(shù)字。要求時(shí)間復(fù)雜度為O(n),空間復(fù)雜度為O(1)。
分析:這是一個(gè)很新穎的關(guān)于位運(yùn)算的題目。
首先考慮這個(gè)問(wèn)題的一個(gè)簡(jiǎn)單版本:一個(gè)整數(shù)數(shù)組里除了一個(gè)數(shù)字之外,其他的數(shù)字都出現(xiàn)兩次,請(qǐng)寫(xiě)程序找出這個(gè)只出現(xiàn)一次的數(shù)字。
這個(gè)問(wèn)題的突破口在哪?題目中數(shù)組的性質(zhì)是只有一個(gè)整數(shù)出現(xiàn)一次,其他的都出現(xiàn)兩次。這樣的話(huà)就使我們想到了異或運(yùn)算的性質(zhì):任何一個(gè)數(shù)字按位異或它自己都等于0,因?yàn)楫惢虻男再|(zhì)是相同為0不同為1。也就是說(shuō)如果從頭到尾依次按位異或數(shù)組中的每一個(gè)整數(shù),那么最終的結(jié)果剛好是那個(gè)只出現(xiàn)一次的數(shù)字。那么兩兩相同的整數(shù)在異或的過(guò)程中等于0抵消了。同時(shí)0與任何整數(shù)按位異或的結(jié)果都是這個(gè)整數(shù)本身。
根據(jù)上面的這個(gè)簡(jiǎn)單為題的解決方案,回到題目中的問(wèn)題。如果能把原數(shù)組分為兩個(gè)子數(shù)組,在每個(gè)子數(shù)組中包含一個(gè)只出現(xiàn)一次的數(shù)字,而其他的數(shù)字都出現(xiàn)兩次。如果能夠這樣拆分原數(shù)組,那么問(wèn)題就變成在拆分的兩個(gè)數(shù)組中分別尋找這兩個(gè)只出現(xiàn)一次的數(shù)字。
那么剩下的問(wèn)題就是根據(jù)什么條件拆分?jǐn)?shù)組?
解決的辦法是:把所有的整數(shù)依次做按位異或運(yùn)算,因?yàn)槠渌挠信鋵?duì)的整數(shù)按位異或的結(jié)果等于0,這樣最后異或的結(jié)果就相當(dāng)于把這兩個(gè)只出現(xiàn)一次的整數(shù)異或,所以想要區(qū)分這兩個(gè)整數(shù),可以從它們異或的結(jié)果上區(qū)分。在它們異或的結(jié)果中找一個(gè)為1的bit位,即為第N位。根據(jù)異或的運(yùn)算原理,那么這兩個(gè)數(shù)的第N位肯定一個(gè)為1一個(gè)為0。根據(jù)第N位是1或者0把整個(gè)數(shù)組分成兩組。就能滿(mǎn)足每個(gè)子數(shù)組包含一個(gè)只出現(xiàn)一次的整數(shù),其他的數(shù)字兩兩配對(duì)的出現(xiàn)在不同的子數(shù)組中。
算法步驟:
(1)依次按位異或數(shù)組中的每一個(gè)整數(shù),得出異或運(yùn)算的結(jié)果。
(2)找到異或運(yùn)算結(jié)果的二進(jìn)制形式中,最低位的1對(duì)應(yīng)的下標(biāo)值。把這個(gè)位作為區(qū)分兩個(gè)整數(shù)的標(biāo)準(zhǔn)。
(3)根據(jù)區(qū)分標(biāo)準(zhǔn),把整個(gè)數(shù)組分成兩個(gè)子數(shù)組,分別求它們的異或運(yùn)算值,得到兩個(gè)運(yùn)算結(jié)果就是要求的兩個(gè)只出現(xiàn)一次的整數(shù)。
函數(shù)聲明:
bool FindTwoSingleNums(int nums[], int nLength, int &a, int &b); bool IsBit1(int num, uint indexBit); uint FindFirstBitIs1(int num);代碼實(shí)現(xiàn):
bool FindTwoSingleNums(int nums[], int nLength, int &a, int &b) {if(nLength < 2){return false;}int resXOR = 0;for(int i = 0; i < nLength; i++){resXOR ^= nums[i];}//foruint index = FindFirstBitIs1(resXOR);for(int i = 0; i < nLength; i++){if(IsBit1(nums[i], index)){a ^= nums[i];}else{b ^= nums[i];}}//for }//FindTwoSingleNums()//找到一個(gè)數(shù)的最低位的1的下標(biāo)值,下標(biāo)從零開(kāi)始 uint FindFirstBitIs1(int num) {uint index = 0;uint maxIndex = sizeof(num) * 8;//注意運(yùn)算符的優(yōu)先級(jí)while(((num & 1) == 0) && (index < maxIndex)){num >>= 1;++index;}//whilereturn index; }//FindFirstBitIs1()//下標(biāo)從0開(kāi)始,所以向右移動(dòng)的位數(shù)為indexBit bool IsBit1(int num, uint indexBit) {num >>= indexBit;return num & 1; }//IsBit1PS:關(guān)鍵詞—>相同數(shù)字按位異或結(jié)果為0,并根據(jù)所有元素異或結(jié)果第一個(gè)出現(xiàn)1的位置(出現(xiàn)1的最低位)把數(shù)組分成兩部分。
轉(zhuǎn)載于:https://www.cnblogs.com/stemon/p/4237301.html
總結(jié)
以上是生活随笔為你收集整理的算法题:找出整数数组中两个只出现一次的数字的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 利用 Win32 启动和检测 UWP A
- 下一篇: 极路由安全设计架构分析