Leetcode 1658. X をゼロに減らすための最小限の操作プレフィックスと配列の質問


  1. X をゼロに減らすための最小限の操作

整数配列 nums と整数 x が与えられます。1 回の操作で、配列 nums から左端または右端の要素を削除し、その値を x から減算できます。これにより、将来の操作のために配列が変更されることに注意してください。

可能であれば x を正確に 0 に減らすための演算の最小数を返し、それ以外の場合は -1 を返します。

例 1:

入力: nums = [1,1,4,2,3]、x = 5
出力: 2
説明: 最適な解決策は、最後の 2 つの要素を削除して x をゼロに減らすことです。
例 2:

入力: nums = [5,6,7,8,9]、x = 4
出力: -1
例 3:

入力: nums = [3,2,20,1,1,3], x = 10
出力: 5
説明: 最適な解決策は、最後の 3 つの要素と最初の 2 つの要素 (合計 5 つの操作) を削除して x を減らすことです。ゼロに。

制約:

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

解決策 1: 推定値、バックサム、および unowned_map を使用します。時間計算量は O(n) である必要があります

class Solution {
    
    
public:
    int minOperations(vector<int>& nums, int x) {
    
    
        int n = nums.size();
        int res = n + 1;
        vector<int> presums(n + 1, 0), backsums(n + 1, 0);
        unordered_map<int, int> backMap;
        for (int i = 1; i <= n; i++) {
    
    
            presums[i] = presums[i - 1] + nums[i - 1];
        }
        for (int i = n; i >= 1; i--) {
    
    
            backsums[i - 1] = backsums[i] + nums[i - 1];
            backMap[backsums[i - 1]] = i - 1;
        }
        for (int i = 0; i <= n; i++) {
    
    
            if (presums[i] == x) {
    
    
                res = min(res, i);
            }
            if (backMap.find(x - presums[i]) != backMap.end()) {
    
    
                res = min(res, i + n - backMap[x - presums[i]]);
            }
        }
        return res == n + 1 ? -1 : res;
    }
};

解決策 2: 推定、バックサム、および二分探索に基づく。推定の各エントリについて、二分探索を使用してバックサム内の x - presums[i] を見つけます。時間計算量は O(nlogn) である必要があります。

class Solution {
    
    
public:
    int minOperations(vector<int>& nums, int x) {
    
    
        int n = nums.size();
        int res = n + 1;
        vector<int> presums(n + 1, 0), backsums(n + 1, 0);
        for (int i = 1; i <= n; i++) {
    
    
            presums[i] = presums[i - 1] + nums[i - 1];
        }
        for (int i = n; i >= 1; i--) {
    
    
            backsums[i - 1] = backsums[i] + nums[i - 1];
        }
        
        for (int i = 0; i <= n; i++) {
    
    
            int target = x - presums[i];
            int start = i, end = n;
            while (start + 1 < end) {
    
    
                int mid = start + (end - start) / 2;
                if (backsums[mid] > target) {
    
    
                    start = mid;
                } else if (backsums[mid] < target) {
    
    
                    end = mid;
                } else {
    
    
                    res = min(res, i + n - mid);    //(i + 1) + (n - mid)
                    break;
                }
            }
            if (backsums[start] == target) res = min(res, i + n - start);
            if (backsums[end] == target) res = min(res, i + n - end);
        }
        return res == n + 1 ? -1: res;
    }
};

おすすめ

転載: blog.csdn.net/roufoo/article/details/132788926