雙周賽352。這題是真的囉嗦,完全不想考慮非暴力以外的方法。

題目

輸入整數陣列nums和整數threshold。

找到最長的子陣列,其始於索引l,止於索引r,滿足0 <= l <= r < nums,並且符合以下條件:

  • nums[l] % 2 == 0
  • 對於所有介於[l, r - 1]的索引i,滿足nums[i] % 2 != nums[i + 1] % 2
  • 對於所有介於[l, r]的索引i,滿足nums[i] <= threshold

求滿足以上條件的最長子陣列長度。

解法

暴力窮舉所有子陣列,並檢查是否符合條件。

只有在子陣列長度大於當前最長長度ans時,才去檢查是否合法,可以加速不少。

時間複雜度O(N^3)。
空間複雜度O(N)。

class Solution:
    def longestAlternatingSubarray(self, nums: List[int], threshold: int) -> int:
        
        def ok(a):
            if a[0]%2!=0:
                return False
            for x in a:
                if x>threshold:
                    return False
            for x,y in pairwise(a):
                if x%2==y%2:
                    return False
            return True
        
        N=len(nums)
        ans=0
        for l in range(N):
            for r in range(l,N):
                # if ok(nums[l:r+1]):
                #     ans=max(ans,r-l+1)
                if r-l+1>ans and ok(nums[l:r+1]):
                    ans=r-l+1
                    
        return ans

枚舉左邊界,並嘗試擴展右邊界。
在擴展右邊界的同時進行檢查,空間和時間都節省很多。

時間複雜度O(N^2)。
空間複雜度O(1)。

class Solution:
    def longestAlternatingSubarray(self, nums: List[int], threshold: int) -> int:
        N=len(nums)
        ans=0
        
        for left in range(N):
            if nums[left]%2==0 and nums[left]<=threshold:
                right=left
                while right+1<N and nums[right]%2!=nums[right+1]%2 and nums[right+1]<=threshold:
                    right+=1
                ans=max(ans,right-left+1)
                
        return ans

可以發現,當一個區間[left,right]結束擴展時,下一個區間的起點一定會大於right,因為選擇介於left和right之間的索引作為左邊界,他的右邊界都一定是right,只會得到更小的結果。
所以可以直接left跳到right+1,實際上每個索引只會被訪問到一次。

時間複雜度O(N)。
空間複雜度O(1)。

class Solution:
    def longestAlternatingSubarray(self, nums: List[int], threshold: int) -> int:
        N=len(nums)
        ans=0
        left=0
        
        while left<N:
            if nums[left]%2==1 or nums[left]>threshold:
                left+=1
            else:
                right=left
                while right+1<N and nums[right+1]%2!=nums[right]%2 and nums[right+1]<=threshold:
                    right+=1
                ans=max(ans,right-left+1)
                left=right+1
                
        return ans