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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

leetcode 算法解析(一):260. Single Number III(C++版本和自己的注解)

發布時間:2023/12/20 c/c++ 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 leetcode 算法解析(一):260. Single Number III(C++版本和自己的注解) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這個題來自《劍指offer》但是書上上感覺講解不太詳細,還是看博客吧(我把下面博客改寫成了C++版本運行通過)

注意這個題的相關代碼中,輸入的數組只能有兩個數出現一次,如果有第三個數出現一次,那么這個代碼就會失效。

總結下算法思路:

假設原始數組中只出現一次的元素是A和B,原始數組為{A,E,C,D,C,D,E,B}

主要是利用異或的交換律。

先把所有數字按次序進行異或運算,得到的結果必然是A⊕B,因為其他元素都是出現兩次的,根據異或運算的交換律有

A⊕E⊕C⊕D⊕C⊕D⊕E⊕B=A⊕B⊕C⊕C⊕D⊕D⊕E⊕E=A⊕B

這個A⊕B中可能有多個比特位是1,我們取最右側的一個bit(其實其他bit也行)

先把原始數組拆成兩份,怎么拆呢?利用上面的那個A⊕B的最右側的值為1的bit位(其他位置為0),

和這個bit位&結果為非0的歸為1組并進行異或運算(異或運算的初始值為0),

和這個bit位&結果為0的歸為另外1組并進行異或運算(異或運算的初始值為0)

在歸為一組的同時進行異或運算,所以其實這里再次使用了異或運算的交換律,

因為C,D,E都出現兩次,無論歸為哪一組,異或結果都是0,我們可以不關心。

好了,所以其實就是剩下的A和B與上面的bit進行運算的結果是最關鍵的。

因為A⊕B的最右側的bit位表示了A和B在二進制的某位上的不一致,也就是在這個位上必定一個是1,一個是0,

所以當A和(A⊕B的最右側的bit位)進行&運算時,要么相等,要么不相等。

相等時丟入其中一組去做異或運算,因為其他元素都是出現兩次,所以最終異或結果肯定是這個只出現一次的數

不相等時丟入其中一組去做異或運算,因為其他元素都是出現兩次,所以最終異或結果肯定是這個只出現一次的數

文章轉載自:

https://segmentfault.com/a/1190000004886431

260.Single Number II 原題鏈接

  • 本題其實算是比較簡單,在 leetcode 上也只是 medium 級別,ac 率也很高,最好先自己嘗試,本文只是單純的記錄一下自己整體的思路;

  • 在閱讀本文章之前,最好先解鎖本題的簡單模式 136.Single Number,這對理解本題有較大的幫助;

  • 還有很多細節作者都沒有寫進去,是為了留給讀者一點思考的空間,其實是因為懶;

  • 由于作者個人水平等原因,出現錯誤在所難免,還望各位看官海涵。

注意 Note 中的第一個條件:The order of the result is not important.,這個條件非常重要,這關系到算法的正確性。


然后給出整個算法的具體思路,假設數組中兩個不同的數字為 A 和 B;

  • 通過遍歷整個數組并求整個數組所有數字之間的 XOR,根據 XOR 的特性可以得到最終的結果為 AXORB = A XOR B;

  • 通過某種特定的方式,我們可以通過 AXORB 得到在數字 A 和數字 B 的二進制下某一位不相同的位;因為A 和 B 是不相同的,所以他們的二進制數字有且至少有一位是不相同的。我們將這一位設置為 1,并將所有的其他位設置為 0,我們假設我們得到的這個數字為 bitFlag;

  • 那么現在,我們很容易知道,數字 A 和 數字 B 中必然有一個數字與上 bitFlag 為 0;

  • ?因為bitFlag 標志了數字 A 和數字 B 中的某一位不同,那么在數字 A 和 B 中的這一位必然是一個為 0,另一個為 1

  • 而我們在 bitFlag 中將其他位都設置為 0,那么該位為 0 的且只出現一次的數字& bitFlag 就等于 0,而該位為 1 的且只出現一次的數字與上 bitFlag 就等于 bitFlag

  • 現在問題就簡單了,我們只需要在循環一次數組,將與上 bitFlag 為 0 的數字進行 XOR 運算,與上 bitFlag 不為 0 的數組進行獨立的 XOR 運算。那么最后我們得到的這兩個數字就是 A 和 B。

  • 先給出具體實現,引用自 proron's Java bit manipulation solution,我修改了部分代碼以便于理解:

    #include<iostream> ? using namespace std; int* singleNumber(int* nums,int length) {int AXORB = 0;for (int i = 0; i<length; i++){AXORB ^= nums[i];}//這里利用的是異或運算的交換律,最終結果等于兩個只出現一次的元素的抑或//即:AXORB=A 異或 B// pick one bit as flagcout << "AXORB=" << AXORB << endl;cout << "AXORB-1=" << AXORB - 1 << endl;int bitFlag = (AXORB & (~(AXORB - 1)));cout << "bigFlag=" << bitFlag << endl;//使用這個bitFlag來給原始數組進行分類,分成2類,//之所以分成兩類是希望每一個類都有一個只出現一次的數即A或者Bint *res = new int[2];res[0] = res[1] = 0;//這里不要忘記初始化。for (int i = 0; i<length; i++){cout << "i=" << i << endl;cout << "nums[i]=" << nums[i] << endl;if ((nums[i] & bitFlag) == 0){cout << "res[0]=" << res[0] << endl;res[0] ^= nums[i];//這里再次利用異或運算的交換律。//因為分成了兩類,所以其中一類不停地運算,最終結果一定是只出現一次的數。}//例如6^3^5^5^3=6^3^3^5^5=6//下面的else中同理else {cout << "res[1]=" << res[1] << endl;res[1] ^= nums[i];}cout << "-------------------------" << endl;}return res; }int main() {int nums[8] = { 2,4,3,6,3,2,5,5 };int *result = singleNumber(nums,sizeof(nums)/sizeof(nums[0]));cout << "--------main----------" << endl;cout << result[0] << endl;cout << result[1] << endl;cin.get();cin.get();return 0; }

    接下來,我們一行行的解析代碼:

    int AXORB = 0; for(int num: nums){AXORB ^= num; }

    這段代碼在 136.Single Number 已經解析過,很容易理解最后得到的結果:假設數組中不同的數字為 A 和 B,那么 最后得到的結果是 A XOR B。

    隨后的這一行代碼是整個算法中的難點:

    //pick one bit as flag int bitFlag = (AXORB & (~ (AXORB - 1)));

    這一行代碼的作用是:找到數字 A 和數字 B 中不相同的一位,并將該位設置為 1,其他位設置為 0;
    根據 XOR 的定義,我們知道,在 AXORB 中,為 1 的位即 A 和 B 不相同的位,AXORB 中為 0 的位即 A 和 B 中相同的位
    所以,要找到 A 和 B 中不相同的位,只需要找到在 AXORB 中從右往左第一個為 1 的位,保留該位并將其他位置為 0 即可。

    //其實這一行與下面的代碼等價,但是論逼格就差遠了(手動斜眼 public static int f(int num){int times = 0;while(num > 0){if(num % 2 == 1){break;}times++;num = num >> 1;}return 1 << times; } //下面這個返回 true System.out.println(Stream.iterate(1, num -> num + 1).limit(Integer.MAX_VALUE).allMatch(num -> f(num)==(num & (~(num -1)))));

    我們可以把這一行代碼解析為三步:

    int tmp0 = AXORB - 1;
    • 假設 AXORB 從右往左出現的第一位非 0 數字出現在第k位,那么數字 AXORB 可以表示為,可能等于 0:

    如果 a0 = 1;那么問題非常簡單, AXORB - 1 可以表示為:

    int tmp1 = ~tmp0;

    int bitFlag = AXORB & tmp1;

    由前面假設我們知道 a0=1,所以很明顯, bitFlag = 1;

    如果 a0 != 1,我們同樣很容易得出這一行代碼的作用就是將數字 AXORB 的從右到左第一個出現 1 的位置為 1,其他位全部置為 0。其實一點都不容易,只不過用 laTex 寫數學公式好蛋疼啊,所以偷下懶

    到這里,整個算法基本上就沒什么難點了,大家自行理解吧。

    我了個大槽,我本來只是想試試新學的 laTex,結果他喵的就寫了這么多。大寫加粗的坑


    總結

    以上是生活随笔為你收集整理的leetcode 算法解析(一):260. Single Number III(C++版本和自己的注解)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。