基本資料#
難易度: medium 第一次嘗試: 2025-08-03
- 總花費時間:00:00.00
解題思路#
我們可以通過反向思考來解決這個問題。與其尋找將 x 減少到零的最小操作數,我們可以尋找總和等於 sum(nums) - x 的最大子陣列長度。這是因為如果我們從兩端移除元素來將 x 減少到零,剩餘的元素總和必須等於 sum(nums) - x。所需的最小操作數將是 len(nums) - max_subarray_length。
解法#
反向思考與滑動窗口#
class Solution:
    def minOperations(self, nums: List[int], x: int) -> int:
        
        target_sum = sum(nums) - x
        # 處理邊界情況
        if target_sum < 0:
            return -1
        if target_sum == 0:
            return len(nums)
    
        max_len = 0
        left = sum_now = 0
        # 尋找總和等於 target_sum 的最大子陣列
        for right in range(len(nums)):
            sum_now += nums[right]
            # 如果總和超過目標,則縮小窗口
            while sum_now > target_sum:
                sum_now -= nums[left]
                left += 1
            
            # 如果總和等於目標,則更新最大長度
            if sum_now == target_sum:
                max_len = max(max_len, right - left + 1)
        return len(nums) - max_len if max_len != 0 else -1
演算法分析#
時間複雜度#
- 時間: O(n),其中 n 是輸入陣列的長度
- 空間: O(1),因為我們只使用常數量的額外空間
關鍵洞察#
- 反向思考: 將問題轉換為尋找具有特定總和的最大子陣列
- 滑動窗口: 使用滑動窗口尋找具有目標總和的最長子陣列
- 邊界情況處理: 處理目標總和為負數或零的情況
收穫#
- 反向問題轉換: 這道題展示了如何通過反向思考來簡化解決方案。與其尋找最小操作數,我們尋找最大子陣列長度。 
- 滑動窗口應用: 轉換後的問題成為經典的滑動窗口問題 - 尋找具有特定總和的最長子陣列。 
- 目標總和計算: 關鍵洞察是 - target_sum = sum(nums) - x代表我們想要保留在中間的元素總和。
- 窗口管理: 我們維持一個滑動窗口,並根據當前總和是否等於、超過或小於目標總和來調整其大小。 
- 邊界情況處理: 我們需要處理幾個邊界情況:當目標總和為負數(不可能)、當目標總和為零(移除所有元素)、以及當找不到有效子陣列時。 
- 結果計算: 最終結果是 - len(nums) - max_len,代表我們需要從兩端移除的元素數量。
- 單次遍歷解決方案: 解決方案只需要遍歷陣列一次,對於大型輸入非常高效。 
- 記憶體效率: O(1) 空間複雜度使這個解決方案非常記憶體高效,因為我們只需要幾個變數來追蹤當前狀態。 
遇到的問題#
- 初始方法困惑: 我最初嘗試通過直接從兩端移除元素來解決這個問題,這很複雜且效率低下。關鍵洞察是反向思考方法。 
- 目標總和理解: 理解 - target_sum = sum(nums) - x至關重要。我必須仔細思考這在原始問題的上下文中代表什麼。
- 邊界情況管理: 我必須處理多個邊界情況:負數目標總和、零目標總和,以及不存在有效子陣列的情況。 

