LeetCode: 862. Shortest Subarray with Sum at Least K

LeetCode: 862. Shortest Subarray with Sum at Least K

题目描述

Return the length of the shortest, non-empty, contiguous subarray of A with sum at least K.

If there is no non-empty subarray with sum at least K, return -1.

Example 1:

Input: A = [1], K = 1
Output: 1

Example 2:

Input: A = [1,2], K = 4
Output: -1

Example 3:

Input: A = [2,-1,2], K = 3
Output: 3

Note:

1 <= A.length <= 50000
-10 ^ 5 <= A[i] <= 10 ^ 5 1 <= K <= 10 ^ 9

解题思路 —— 滑动窗口

朴素思想(O(n)^2, TLE)

记 ,前 x 数(包括第 x 个数)的和为 frontSum[x], 则第 i 个数到第 j 个数的和为 frontSum[j]-frontSum[i-1]
遍历 i, j 的情况,求出和大于等于 K, 且长度最小的数组即可。复杂度 O(n^2)

class Solution {
public:
    int shortestSubarray(vector<int>& A, int K) {
        // 前序和
        vector<long long int> frontSum(A.size()+1, 0);
        for(int i = 1; i <= A.size(); ++i)
        {
            frontSum[i] = frontSum[i-1] + A[i-1];
        }

        int ans = -1;
        // 枚举所有情况
        for(int i = 0; i < A.size(); ++i)
        {
            for(int j = i; j < A.size(); ++j)
            {
                if(frontSum[j+1] - frontSum[i] >= K && (ans == -1 || ans > j+1-i))
                {
                    ans = j+1-i;
                    break;
                }
            }
        }

        return ans;

    }
};

滑动窗口(O(n))

实际上,当 frontSum[j]-frontSum[i-1] <= 0, 即表示 ij 的元素和小于等于零,会成为后面的负担(增加长度,却不增加和)。因此,j 后面的元素计算最小长度时,可以不用考虑 ij 这一段。具体操作参考代码注释。

AC 代码

class Solution {
public:
    int shortestSubarray(vector<int>& A, int K) {
        vector<long long int> frontSum(A.size()+1, 0);

        for(int i = 1; i <= A.size(); ++i)
        {
            frontSum[i] = frontSum[i-1] + A[i-1];
        }

        int ans = -1;

        deque<int> begCandidates; 

        // 每一次循环处理: 以 end 为结束的 Shortest Subarray with Sum at Least K
        for(size_t end = 0; end <= A.size(); ++end)
        {
            // 如果 begCandidates.back() 到 end 的和是负的,
            // 则计算 end 之后的 “以 end 为结束的 Shortest Subarray with Sum at Least K”, 
            // 不再需要从 begCandidates.back() 开头子数组
            while(!begCandidates.empty() && frontSum[end] - frontSum[begCandidates.back()] <= 0)
            {
                begCandidates.pop_back();
            }

            // 如果 begCandidates.front() 到 end 的和大于等于 K, 则其可能是备选方案
            while(!begCandidates.empty() && frontSum[end] - frontSum[begCandidates.front()] >= K)
            {
                // 如果 begCandidates.front() 到 end 的和大于等于 K, 
                // 则后面的计算不再需要 begCandidates.front() 
                // 因为,begCandidates.front()为起始,和大于等于 K 的,
                // 最小距离一定小于等于 end - begCandidates.front()。
                int beg = begCandidates.front();
                begCandidates.pop_front();

                if(ans == -1) ans = end - beg;
                else ans = min(ans, (int)end - beg);
            }

            begCandidates.push_back(end);
        }

        return ans;

    }
};
全部评论

相关推荐

牛客101244697号:这个衣服和发型不去投偶像练习生?
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务