【Python】where cut query melt函式用法
阿新 • • 發佈:2020-09-08
題目描述
一個整型陣列 nums 裡除兩個數字之外,其他數字都出現了兩次。請寫程式找出這兩個只出現一次的數字。要求時間複雜度是\(O(n)\),空間複雜度是\(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
來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof
程式碼實現
class Solution { public: vector<int> singleNumbers(vector<int>& nums) { int diff = 0; for(auto nt = nums.begin(); nt != nums.end(); nt++) diff ^= (*nt); int flag = diff & (-diff); vector<int> result(2, 0); for(auto nt = nums.begin(); nt != nums.end(); nt++) { if((*nt) & flag) result[0] ^= (*nt); else result[1] ^= (*nt); } return result; } };
思路解析
- 題目的重點是要時間複雜度\(O(n)\),空間複雜度\(O(1)\),考慮位運算的方式;
- 基本的位運算邏輯:
- 使用邏輯異或(\(\oplus\))來區分未成對出現的數字
\(0 \oplus 0 = 0\),\(0 \oplus 1 = 1\); - 邏輯異或(\(\oplus\))運算滿足結合律和交換律;
因此,對所有的數字進行異或運算,由於只有兩個數字(假設為\(a\)和\(b\))未重複出現,則異或運算的結果是\(a\oplus b\)。
\(a_1 \oplus a_1 \oplus a_2 \oplus a_2 \oplus \cdots a_n \oplus a_n \oplus k = k\)
- 使用邏輯異或(\(\oplus\))來區分未成對出現的數字
- 得到\(a\oplus b\)後,我們需要想一個辦法來將
nums
分組,考慮所有的數字都可以用二進位制表示,則可根據某一位是\(0\)或\(1\)來對nums
進行分組,且要保證\(a\)和\(b\)不在同組,採用的分組方式如下:- 在計算機中,整形數字採用補碼的形式表示,正數的補碼等於其原碼,負數的補碼等於其反碼+1,以8位
int
型別為例:
int s = 8
,原碼00000100
,反碼00000100
,補碼00000100
int s =-8
,原碼10000100
,反碼11111011
,補碼11111100
- 可知:
s & (-s) = 00000100
,僅有1位數字為\(1\)(s
的最低位\(1\)),且s
本身的該位數字也為1,可利用這一特性,對原陣列nums
進行分類。 - 如何確保\(a\)和\(b\)不在同一分組?
已知\(d = a\oplus b\),則\(d\)的最低位\(1\)一定可以區分\(a\)和\(b\)(異或運算的定義)
則根據\(d\)的某一位\(1\)對原陣列進行分組,必定可保證\(a\)和\(b\)不同組。
- 在計算機中,整形數字採用補碼的形式表示,正數的補碼等於其原碼,負數的補碼等於其反碼+1,以8位
- 分組之後的事情就簡單了,由於異或運算滿足結合律和交換律,且相同的數字一定被分在的同一組,而\(a\)和\(b\)不同組,對每一組分別進行異或運算,最後兩組得到的結果就分別是\(a\)和\(b\)。