LeetCode每日一題 2021/5/22 810. 黑板異或遊戲
題目描述
黑板上寫著一個非負整數陣列 nums[i] 。Alice 和 Bob 輪流從黑板上擦掉一個數字,Alice 先手。如果擦除一個數字後,剩餘的所有數字按位異或運算得出的結果等於 0 的話,當前玩家遊戲失敗。 (另外,如果只剩一個數字,按位異或運算得到它本身;如果無數字剩餘,按位異或運算結果為 0。)
換種說法就是,輪到某個玩家時,如果當前黑板上所有數字按位異或運算結果等於 0,這個玩家獲勝。
假設兩個玩家每步都使用最優解,當且僅當 Alice 獲勝時返回 true。
示例
輸入: nums = [1, 1, 2] 輸出: false 解釋: Alice 有兩個選擇: 擦掉數字 1 或 2。 如果擦掉 1, 陣列變成 [1, 2]。剩餘數字按位異或得到 1 XOR 2 = 3。那麼 Bob 可以擦掉任意數字,因為 Alice 會成為擦掉最後一個數字的人,她總是會輸。 如果 Alice 擦掉 2,那麼陣列變成[1, 1]。剩餘數字按位異或得到 1 XOR 1 = 0。Alice 仍然會輸掉遊戲。
提示
- 1 <= N <= 1000
- 0 <= nums[i] <= 2^16
方法:數學
思路
根據遊戲規則,輪到某個玩家時,如果當前黑板上所有數字異或結果等於 0,則當前玩家獲勝。由於 Alice 是先手,因此如果初始時黑板上所有數字異或結果等於 0,則 Alice 獲勝。
下面討論初始時黑板上所有數字異或結果不等於 0 的情況。
由於兩人交替擦除數字,且每次都恰好擦掉一個數字,因此對於這兩人中的任意一人,其每次在擦除數字前,黑板上剩餘數字的個數的奇偶性一定都是相同的。
這啟發我們從陣列 nums 長度的奇偶性來討論。如果 nums 的長度是偶數,先手 Alice 是否有可能失敗呢?假設 Alice 面臨失敗的狀態,則只有一種情況,即無論擦掉哪一個數字,剩餘所有數字的異或結果都等於 0。
下面證明這是不可能的。設陣列 nums 的長度為 n,n 是偶數,用 ⊕ 表示異或,記 S 為陣列 nums 的全部元素的異或結果,則有
記 Si 為擦掉 nums[i] 之後,剩餘所有數字的異或結果,則有
等式兩邊同時異或 nums[i],由於對任意整數 x 都有 x⊕x=0,得
如果無論擦掉哪一個數字,剩餘的所有數字異或結果都等於 0,即對任意 0≤i<n,都有 Si =0。因此對所有的 Si
異或結果也等於 0,即
將 Si=S⊕nums[i] 代入上式,並根據異或運算的交換律和結合律化簡,有
上述計算中,第 3 行的左邊括號為 n 個 S 異或,由於 n 是偶數,因此 n 個 S 異或的結果是 0。
根據上述計算,可以得到 S=0,與實際情況 S≠0 矛盾。
因此當陣列的長度是偶數時,先手 Alice 總能找到一個數字,在擦掉這個數字之後剩餘的所有數字異或結果不等於 0。
在 Alice 擦掉這個數字後,黑板上剩下奇數個數字,無論 Bob 擦掉哪個數字,留給 Alice 的一定是黑板上剩下偶數個數字,此時 Alice 要麼獲勝,要麼仍可以找到一個數字,在擦掉這個數字之後剩餘的所有數字異或結果不等於 0,因此 Alice 總能立於不敗之地。
同理可得,當陣列的長度是奇數時,Alice 在擦掉一個數字之後,留給 Bob 的一定是黑板上剩下偶數個數字,因此 Bob 必勝。
綜上所述,當且僅當以下兩個條件至少滿足一個時,}Alice 必勝:
陣列 nums 的全部元素的異或結果等於 0;
陣列 nums 的長度是偶數。
程式碼實現時,可以先判斷陣列 nums 的長度是否是偶數,當長度是偶數時直接返回 true,當長度是奇數時才需要遍歷陣列計算全部元素的異或結果。該實現方法在陣列長度是偶數時只需要 O(1) 的時間即可得到答案。
Java程式碼
class Solution {
public boolean xorGame(int[] nums) {
if(nums.length % 2 == 0) {
return true;
}
int sum = 0;
for(int num : nums) {
sum = sum ^ num;
}
return sum == 0;
}
}
時間複雜度:O(n)。其中 n 是陣列 nums 的長度。最壞情況下,需要遍歷陣列一次,計算全部元素的異或結果。
空間複雜度:O(1)