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;

    }
};
全部评论

相关推荐

机智的豹子有点心碎:UU我还在找工作还没找到,一直在搜简历怎么改,总结了这些: 1.SEO:简历根据每一个岗位定制化:使用这个岗位中所描述的工作的词,它要求什么技能就把自己的技能描述成什么样子,把SEO用在自己身上(把我的简历和个人特质,当成一个热门产品来做 “搜索引擎优化”),让HR能用最低的门槛看到我 2."顺序:把岗位要求的技能跟经历放在简历的最开头、最显眼的位置" 3.包装:简历是一个最终交付说明书,只要最终学习成长做得到就可以,在合适的范围内自我吹捧(我这个人怎么能够在HR的角度被迅速的看懂和看到,减轻HR的工作压力) 4.每点加小标题​:用6~10字概括该段内容,便于面试官快速抓取信息。 5.避免空泛描述​:拒绝“培养了组织能力”等泛泛而谈,替换为具体行动和成果。 6."使用“三段式结构”​​:每段经历按“为什么做-做了什么-结果如何”展开: ​a) 为什么做​:痛点或目标(例如“品牌声量不足”) ​b) 做​了什么:方法论(例如“趋势洞察+竞品对标+人群细分”) ​c) 结果如何​:量化成果或影响(例如“推动客户投放20万预算”)" 7.量化成果​:用数字体现工作成效(如“整理500+份资料”“撰写2万字报告”)。 这些有的是我想去的岗的,如果对你有用的话按需修改就好~加油,早日上岸!
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务