Skip to content

LeetCode: 1658-Minimum Operations to Reduce X to Zero 解題記錄

Last Updated on 2022-06-11 by Clay

題目

You are given an integer array nums and an integer x. In one operation, you can either remove the leftmost or the rightmost element from the array nums and subtract its value from x. Note that this modifies the array for future operations.

Return the minimum number of operations to reduce x to exactly 0 if it is possible, otherwise, return -1.

Example 1:

Input: nums = [1,1,4,2,3], x = 5
Output: 2
Explanation: The optimal solution is to remove the last two elements to reduce x to zero.

Example 2:

Input: nums = [5,6,7,8,9], x = 4
Output: -1

Example 3:

Input: nums = [3,2,20,1,1,3], x = 10
Output: 5
Explanation: The optimal solution is to remove the last three elements and the first two elements (5 operations in total) to reduce x to zero.

Constraints:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 104
  • 1 <= x <= 109

題目的意思很單純,我們有一組陣列,和一個目標值 x。我們只能從該陣列的左邊或右邊開始移除,然後我們要讓移除的值加總正好為 x。當然我們可能會有很多種方法得到跟 x 一樣的移除值,但我們需要找到最少操作的步驟的數量並回傳。


解題思路

滑動窗口(sliding window)

一開始我想要使用 DFS 從左右兩側減去值來遍歷所有可能的答案;但後來發現滑動窗口sliding window)可能更直觀。

首先我們從左側開始,逐漸將值加總。

如果值正好等於『完整陣列加總值 - x』(也就是目標值),則說明目前並未加進來的值正好就是我們答案的操作步驟。由於我們可能會存在很多不同的操作步驟的解答,所以需要另外一個數值記錄最大的當前加總陣列長度(因為操作步驟最少)。

而一但當前加總值超過了目標值,則我們必須逐步刪除左側值,直到當前加總值小於目標值。


滑動窗口複雜度

Time complexityO(n)
Space complexityO(1)


滑動窗口 C++ 範例程式碼

class Solution {
public:    
    int minOperations(vector<int>& nums, int x) {
        // Init        
        int target = accumulate(nums.begin(), nums.end(), 0) - x;
        int sum = 0;
        int max_len = 0;
        int left = 0;
        bool isFound = false;
        
        // Sliding window
        for (int right=0; right<nums.size(); ++right) {
            sum += nums[right];
            
            // If the current sum is too large, reduce it.
            while (left <= right && sum > target) {
                sum -= nums[left];
                ++left;
            }
            
            // Record the maximum length
            if (sum == target) {
                isFound = true;
                max_len = max(max_len, right-left+1);
            }
        }
        
        return isFound ? nums.size() - max_len : -1;
    }
};



滑動窗口 Python 範例程式碼

class Solution:
    def minOperations(self, nums: List[int], x: int) -> int:
        # Init        
        target = sum(nums) - x
        _sum = 0
        max_len = 0
        left = 0
        isFound = False
        
        # Sliding window
        for right in range(len(nums)):
            _sum += nums[right]
            
            # If the current sum is too large, reduce it.
            while left <= right and _sum > target:
                _sum -= nums[left]
                left += 1
            
            # Record the maximum length
            if _sum == target:
                isFound = True
                max_len = max(max_len, right-left+1)
        
        return len(nums)-max_len if isFound else -1

References


Read More

Leave a Reply