[路飞]_程序员必刷力扣题: 1658. 将 x 减到 0 的最小操作数

166 阅读1分钟

「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战

1658. 将 x 减到 0 的最小操作数

给你一个整数数组 nums 和一个整数 x 。每一次操作时,你应当移除数组 nums 最左边或最右边的元素,然后从 x 中减去该元素的值。请注意,需要 修改 数组以供接下来的操作使用。

如果可以将 x 恰好 减到 0 ,返回 最小操作数 ;否则,返回 -1 。

示例1:

输入: nums = [1,1,4,2,3], x = 5
输出: 2
解释: 最佳解决方案是移除后两个元素,将 x 减到 0 。

示例2:

输入: nums = [5,6,7,8,9], x = 4
输出: -1

示例3:

输入:nums = [3,2,20,1,1,3], x = 10
输出:5
解释:最佳解决方案是移除后三个元素和前两个元素(总共 5 次操作),将 x 减到 0 。

提示:

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

前缀和后缀和+遍历

思路

有题意可知,我们需要从数组的前面或者后面依次选择元素,将选择的元素相加正好等于目标值x

这里我们用前缀和和后缀和来记录对应的值,这样我们就可以直接用前缀和第p位和后缀和第q位相加来判断是否等于目标值x了

具体实现:

  • 首先求前缀和before和后缀和after,如果有首位或者末位直接返回1即可
  • 声明p和q分别指向前缀和第一位和后缀和第len-1位,while循环条件为p,q有效,且p < q
    • 如果当前总和total小于x,那么q--
    • 如果当前总和total等于x,那么给min赋值,如果为-1则直接赋值,否则与min比较去最小值。此时已经等于x了,没必要继续q--了,所以p++一次,并且while循环条件total>x,那么q++
    • 如果当前总和total大于x,那么p++一次,并且while循环条件total>x,那么q++

最后返回min即可

var minOperations = function (nums, x) {
    var min = -1;
    var len = nums.length;
    var before = Array(len).fill(0);
    var after = Array(len).fill(0);

    // 设置初始值,并判断是否符合答案
    before[0] = nums[0];
    after[len - 1] = nums[len - 1];
    if (nums[0] === x || nums[len - 1] === x) return 1;
    // 前缀和、后缀和   并记录是否有单边满足条件的答案
    for (var i = 1; i < len; i++) {
        before[i] = before[i - 1] + nums[i];
        after[len - 1 - i] = after[len - i] + nums[len - 1 - i];
        if (before[i] === x || after[len - 1 - i] === x) {
            if (min === -1) {
                min = i + 1;
            } else {
                min = Math.min(i + 1, min);
            }
        }
        if (before[i] >= x && after[len - 1 - i] >= x) {
            break;
        }
    }

    // 特殊情况
    // [1,1,2,3,5,6,7,2,2,3]   7  4+0 、 0+3、2+2、3+1
    // 这里min最少>=2
    var p = 0,
        q = len - 1;
    while (p >= 0 && q <= len - 1 && p < q) {
        var total = before[p] + after[q];
        if (total < x) {
            q--;
        }
        if (total > x) {
            p++
            while (before[p] + after[q] > x && q < len) {
                q++
            }
        }
        if (total === x) {
            if (min === -1) {
                min = p + 1 + len - q;
            } else {
                min = Math.min(p + 1 + len - q, min);
            }
            p++
            while (before[p] + after[q] > x && q < len) {
                q++
            }
        }
    }

    return min;
};