Description
給定一個非空整數陣列
nums,其中每個元素都出現兩次,只有一個元素只出現一次。找出那個只出現一次的元素。要求線性時間複雜度且不使用額外空間。
Example:
Input: nums = [4,1,2,1,2] Output: 4
Intuition#
核心思路:XOR 的特性 a ^ a = 0,將所有數字 XOR 起來,成對的會抵消,剩下唯一的那個。
- 如果用 Hash Map 記錄出現次數,可以 O(n) 時間、O(n) 空間解決
- XOR 有三個關鍵性質:a ^ 0 = a、a ^ a = 0、XOR 滿足交換律和結合律
- 因此將所有數字依序 XOR,成對出現的數字會互相抵消為 0,最後剩下唯一的數字
Approaches#
1: Hash Map 計數#
- 概念: 用 Hash Map 記錄每個數字的出現次數,再找出只出現一次的數字
- 時間複雜度:
O(n)- 遍歷陣列兩次 - 空間複雜度:
O(n)- Hash Map 儲存最多 n/2 + 1 個鍵
class Solution {
fun singleNumber(nums: IntArray): Int {
val count = HashMap<Int, Int>()
for (num in nums) {
count[num] = count.getOrDefault(num, 0) + 1
}
for ((key, value) in count) {
if (value == 1) return key
}
throw IllegalArgumentException("No single number found")
}
}⭐2: XOR#
- 概念: 利用 XOR 的性質,將所有數字 XOR 起來,成對的會抵消為 0,最後結果就是唯一的數字
- 時間複雜度:
O(n)- 遍歷陣列一次 - 空間複雜度:
O(1)- 只用一個變數
class Solution {
fun singleNumber(nums: IntArray): Int {
var result = 0
for (num in nums) {
result = result xor num
}
return result
}
}補充:Kotlin reduce 寫法
利用 Kotlin 的 reduce 函數可以更簡潔地表達:
class Solution {
fun singleNumber(nums: IntArray): Int {
return nums.reduce { acc, num -> acc xor num }
}
}🔑 Takeaways#
- Pattern: XOR 消除配對是位元操作的經典技巧
- 關鍵技巧: a ^ a = 0 和 a ^ 0 = a 這兩個性質可以推廣到許多「找唯一 / 找差異」的問題