題目描述:給定正整數陣列 nums,若一個子陣列中任意兩個不同元素的按位 AND(bitwise AND)為 0,稱此子陣列為「nice subarray」。求最長 nice subarray 的長度。
解題思路(位元遮罩滑動視窗):
「任意兩個元素 AND = 0」等價於「任意兩個元素沒有共用的 bit」,亦即視窗內所有元素在 32 個 bit 位上互不衝突(每個 bit 最多被一個元素使用)。
用 usedBits 位元遮罩記錄視窗內所有元素所佔用的 bit 集合(usedBits = 視窗內所有元素的 OR)。若所有元素互不共用 bit,則 usedBits 的各位元恰好對應到唯一的某個元素。
演算法:
usedBits = 0,左指針 l = 0。r 向右擴展,嘗試加入 nums[r]。nums[r] & usedBits != 0(有共用 bit),從左側縮小視窗:
usedBits ^= nums[l](XOR 清除 nums[l] 佔用的 bit,因無共用 bit 時 XOR 等於清除)l++nums[r] & usedBits == 0。nums[r] 加入視窗:usedBits |= nums[r]。r - l + 1。關鍵:移除 nums[l] 時用 usedBits ^= nums[l](等同於 usedBits &= ~nums[l],但 XOR 在無共用 bit 的情況下更高效)。
時間複雜度:O(n) — 雙指針各最多移動 n 次,每次操作 O(1),整體線性。
空間複雜度:O(1) — 只使用常數個整數變數(usedBits、l、ans),無需額外空間。
1. usedBits = 0, l = 0, ans = 1.
2. For r in 0..n-1:
a. While (usedBits AND nums[r]) != 0:
- usedBits XOR= nums[l] (remove nums[l]'s bits).
- l++.
b. usedBits OR= nums[r] (add nums[r] to window).
c. ans = max(ans, r - l + 1).
3. Return ans.枚舉所有子陣列 [l, r],維護一個 usedBits 遮罩,逐一加入元素時檢查是否有共用 bit。時間 O(n²),空間 O(1)。當 n = 10⁵ 時有 10¹⁰ 次操作,超時;適合驗證正確性。
此問題不適合排序法,因為子陣列要求連續性(元素順序不能改變),排序後連續性被破壞。此方法不適用。
對每個子陣列統計每個 bit 位的使用次數,若所有 bit 計數均 ≤ 1 則為 nice subarray。本質與雙重迴圈相同,時間 O(n² · 32) = O(n²),但常數更大,不推薦。
usedBits ^= nums[l] 能正確清除 nums[l] 的 bit,前提是視窗內沒有任何兩個元素共用 bit。若允許共用 bit(條件放鬆),該清除操作如何安全地改寫?