20221026 - 862. Shortest Subarray with Sum at Least K 和至少为 K 的最短子数组(前缀和+单调双端队列)

108 阅读1分钟

Given an integer array nums and an integer k, return the length of the shortest non-empty subarray of nums with a sum of at least k. If there is no such subarray, return -1.

A subarray is a contiguous part of an array.

Example 1

Input: nums = [1], k = 1
Output: 1

Example 2

Input: nums = [1,2], k = 4
Output: -1

Example 3

Input: nums = [2,-1,2], k = 3
Output: 3

Constraints

  • 1 <= nums.length <= 1e5
  • -1e5 <= nums[i] <= 1e5
  • 1 <= k <= 1e9

Solution

超时的暴力:

class Solution {
public:
    int shortestSubarray(vector<int>& nums, int k) {
        for (int i = 1; i <= nums.size(); i++) {
            for (int j = 0; j < nums.size(); j++) {
                int sum = 0;
                for (int l = j; j + i <= nums.size() && l < j + i; l++) {
                    sum += nums[l];
                }
                if (sum >= k) return i;
            }
        }
        return -1;
    }
};

加上前缀和数组优化后还是超时:(求区间元素和以后要想到前缀和优化了)

class Solution {
public:
    int shortestSubarray(vector<int>& nums, int k) {
        vector<int> presum(nums.size());
        presum[0] = nums[0];
        for (int i = 1; i < nums.size(); i++) {
            presum[i] = presum[i - 1] + nums[i];
        }
        for (int i = 1; i <= nums.size(); i++) {
            for (int j = 0; j + i - 1 < nums.size(); j++) {
                if (presum[j + i - 1] - presum[j] + nums[j] >= k) return i;
            }
        }
        return -1;
    }
};

前缀和 + 单调双端队列:

class Solution {
public:
    int shortestSubarray(vector<int>& nums, int k) {
        int n = nums.size();
        vector<long> presum(n + 1); //前缀和可能会溢出
        //生成前缀和数组
        presum[0] = 0;
        for (int i = 0; i < n; i++) presum[i + 1] = presum[i] + nums[i];
        //遍历前缀和数组
        deque<int> q;
        int ans = INT_MAX;
        for (int i = 0; i <= n; i++) {
            //判队首
            while (!q.empty() && presum[i] - presum[q.front()] >= k) {
                ans = min(ans, i - q.front());
                q.pop_front();
            }
            //判队尾
            while (!q.empty() && presum[q.back()] >= presum[i]) {
                q.pop_back();
            }
            //遍历入队
            q.push_back(i);
        }
        if (ans == INT_MAX) ans = -1;
        return ans;
    }
};

题目链接:862. 和至少为 K 的最短子数组 - 力扣(LeetCode)