Leetcode 862. 和至少为 K 的最短子数组

本题的题目让新手(比如说我)很容易想到爆搜,两个for循环直接遍历每个子数组,可以很容易得到答案,但是本题作为困难题,难点就是范围较大,用O(n²)的算法必然会爆,我们就要换个思路,我用的方法是前缀和+ 双向队列。

为什么我会想到用前缀和,本题是连续的子数组,并且要求和,连续+求和让我想到了用前缀和,可能有些人不知道啥叫前缀和,即创建一个数组,假设数组为S[n],原数组为A[n],前缀和数组就是使得s[n] = a[0] + a[1] +a[2] ... + a[n],即前n个元素的和。

何为双向队列,即队头和队尾都可以执行插入和删除操作,不像普通队列只能在队尾插入,队头删除。

本题还有一个关键的点,就是答案的子数组长度怎么来的,我在这举个例子

我们可以看出来,在前缀和数组中满足S[n] - S[m] >= k,(n > m) ,即可满足从A[m] 到 A[n]的子数组的和大于等于k,满足题意,那我们怎么找到最小的子数组呢,我们要进行减枝。

比如说上图的S[4] - S[1]是大于K的,S[4] - S[2]也是大于K的,A[1] < 0, 我们可以得出一个结论,如果说S[m] < S[n],(m > n),我们可以略过S[m]这个元素,因为后面的元素必然比S[m]大而且子数组的长度也比S[m]到另一端的距离更短(此处的另一端为S[4]),不难看出只要A[n] < 0,我们可以略过相应的前缀和数组往下搜索。

还是这个例子,我们找到了S[4] - S[1] >= k,我们接下来为了找到更短的,应该调整S[1]的位置,让他往后移动,更加靠近S[4],才能找到最小的,直到栈空

class Solution {
public:
    int shortestSubarray(vector<int>& nums, int k) 
    {
        int n = nums.size();
        int ans = n + 1;
        vector<long> temp;
        long sum = 0;
        temp.push_back(0);
        for(int & num : nums)
        {
            sum += num;
            temp.push_back(sum);
        }
        deque<int> deq;
        for(int i = 0;i < n + 1; i ++)
        {
            while(!deq.empty() && temp[i] <= temp[deq.back()])
            {
                deq.pop_back();
            }
            while(!deq.empty() && temp[i] - temp[deq.front()] >= k)
            {
                int temp1 = i - deq.front();
                deq.pop_front();
                ans = min (ans,temp1);
            }
            deq.push_back(i);
        }
        return ans == n + 1? -1 : ans;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值