LeetCode 2401. Longest Nice Subarray
周賽309。雖然我有順利做出來,但是似乎繞了一些遠路。
題目
輸入由正整數組成的陣列nums。
若某子陣列中,每個元素對其他元素做位元AND運算的結果都為0,則稱此子陣列為好的。
求最長的好的子陣列長度。
注意:長度為1的子陣列永遠是好的。
解法
找最長的子陣列,又是最近熱門的滑動窗口。
若兩個數做AND運算結果為0,則其必定沒有共通的1位元。若好幾個數互相做AND都為0,則每個位置最多只能出現一次1位元,否則必定不為0。
按照以上思路,我們只要維護在哪個位置出現過1位元,在做滑動窗口時,碰到重複位元則縮減左邊界。
因為要多次標記/清除各位元很麻煩,寫成兩個函數add和remove,分別可以將某數字n的1位元全部標記或清除。
列舉nums中每個元素作為窗口右邊界,加入新元素並縮減左邊界之後以窗口大小更新答案。
在add的過程中,如果需要標記的位元已經被占用,則代表有衝突,必須用remove縮減左邊界直到沒有元素衝突為止。
remove就比較單純,查看哪個位置是1位元,清除標記。
標記和清除複雜度都是O(1),每個元素最被標記和清除各一次,共N個元素,整體時間複雜度O(N)。
class Solution:
def longestNiceSubarray(self, nums: List[int]) -> int:
def add(n):
for i in range(30):
if n&(1<<i):
while used[i]:
remove(nums[left])
used[i]=True
def remove(n):
nonlocal left
for i in range(30):
if n&(1<<i):
used[i]=False
left+=1
ans=1
left=0
used=[False]*30
for right,n in enumerate(nums):
add(n)
ans=max(ans,right-left+1)
return ans
其實只要用XOR相消的特性,就可以簡單的把某個數字對應的所有1位元給去掉。
因為只有在新元素n和已選擇的所有數字沒有衝突之下,才會將新的1位元加入(OR運算)。那麼之後將此元素在做一次XOR時,必定能夠還原到原本的狀態。
class Solution:
def longestNiceSubarray(self, nums: List[int]) -> int:
sm=0
ans=1
left=0
for right,n in enumerate(nums):
while sm&n!=0:
sm^=nums[left]
left+=1
sm|=n
ans=max(ans,right-left+1)
return ans