前往
大廳
主題

LeetCode - 421. Maximum XOR of Two Numbers in an Array 解題心得

Not In My Back Yard | 2022-09-05 12:00:08 | 巴幣 0 | 人氣 218

題目連結:


題目意譯:
給定一個整數陣列 nums,回傳 nums[i] XOR nums[j] 最大可能的結果之值,其中 0 ≦ i ≦ j < n。

限制:
1 ≦ nums.length ≦ 2 × 10 ^ 5
0 ≦ nums[i] ≦ 2 ^ 31 - 1



範例測資:
範例 1:
輸入: nums = [3,10,5,25,2,8]
輸出: 28
解釋: 最大結果值為 5 XOR 25 = 28。

範例 2:
輸入: nums = [14,70,53,83,49,91,36,80,92,51,66,70]
輸出: 127


解題思維:
可以看到 O(n ^ 2) 的窮舉作法不可行(其中 n 代表著 nums 的長度),因為 n 值可以到 2 × 10 ^ 5。



現在我們看個例子:
(方便起見以下答案和 nums 中的數字皆是以二進位表示)
假設現在我們基於某種神秘力量知道答案的開頭前幾個位元。假設我們知道答案是 111PX,其中 X 是未知的位元、P 則是下一個我們要試著得知的位元。

而 nums = [10111, 01011, 01001, 00001],接著我們掃過其中所有數字:
當碰到 10111 時,因為答案是 111PX,所以如果 10111 是造成最大值之數對中的其中一個數字的話,則另一個數字應為 010XX (也就是 010 開頭,即 111 XOR 101,這邊的 X 是為了符合長度而已)。而我們有兩個數字都是 010 開頭,即 01011 和 01001。

那我們要選哪個數字呢?可以看到目前的位元 P 是 1 的話,這個結果值必定不會比較小(前提是答案開頭真的是 111 的話,目前我們只是假設自己知道)。基於這個原則,由於現在看到的數字是 10111,其對應於 P 這個位元的數值為 1(標於紅色)。因此要讓 P 為 1,必須要讓另一個數字的對應位元是 0(這樣 XOR 的結果,P 才會是 1),而我們確實有這樣的數字,即 01001。所以我們可以推得 P = 1,也因此答案變為 1111P,可以看到 P 的位置往右移動了一格代表我們可以再繼續推得下一個位元。所以不用繼續看剩下的數字了,因為不管其他數字是怎樣,都改變不了前一個 P 是 1 的事實。可以回到開頭(雖然我們剛好就在開頭)的數字繼續推下一個 P。

與上同理,可以推得最後一個 P 應為 0。因此上列 nums 得出的答案是 11110。



現在我們回到最一開始,也就是完全不知道開頭是什麼的情況下來推論,即目前的答案為 PXXXX。

當碰到 10111 時,因為答案是 PXXXX,所以另一個數字應為 XXXXX(因為目前什麼都不知道,所以所有其他的數字都是候選數字)。而為了讓 P 是 1,也就是要找到 0XXXX 的數字,而 01011 和 01001 這兩個數字符合條件。因此得出第一個 P = 1。自此,我們便可以按照上面的步驟一步一步地推得答案的每個位元應為什麼值。

那剩下的問題就是要怎麼找到特定開頭的數字(例如上面一開始要找符合 010XX 這個條件的數字),而我們可以看到如果 P 現在位於從左邊數來第 C 位位元(從 1 開始數),則代表我們的條件將會是 C 位數長(即要尋找的開頭長度為 C)。因此我們可以在開始掃過 nums 之前,將每個數字的前 C 的位元抓出來丟到一個雜湊表(Hash Table)中,這樣一來要找開頭就會容易許多(也就是只需要到雜湊表中找找看即可)。




此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。

創作回應

更多創作