LeetCode 和至少为 K 的最短子数组(双端队列) vs 长度最小的子数组(滑动窗口)vs 和为K的子数组(前缀和+哈希表)

和至少为 K 的最短子数组
在这里插入图片描述里面的元素可以为负数,故不可以用滑动窗口

涉及知识:

  1. 前缀和数组sum[i] = array[0] + array[1] + ... + array[i-1]
    若要求区间[3, 5]的和,则可用sum[6] - sum[3](注意,为了计算方便,加了sum[0] = 0,即前缀和数组长度为数组长度+1)

  2. 单调双端队列:考虑当前位置i,这时[0, i]的值比区间[0, i-1]还要小,则对于后面的位置,就不需要考虑以i-1为起始的区间了,因为sum[n] - sum[i] > sum[n] - sum[i-1],且前者区间长度更短。故可以把i-1踢出队列。

解法: 从队列中最小的位置开始计算,如果符合条件,就记录答案,并将这个位置踢出队列,因为再往后不会有比这个还要小的符合条件的长度。

class Solution{
public:
    int shortestSubarray(vector<int>& nums, int k) {
        deque<int> dq;    //双端队列
        int min_len = INT_MAX;

        vector<int> sum(nums.size()+1, 0);  //长度+1

        //获取前缀和
        for(int i = 1; i <= nums.size(); i++){
            sum[i] = sum[i-1] + nums[i-1];
        }

        for(int i = 0; i < nums.size(); i++){
            while(dq.size() > 0 && sum[dq.back()] >= sum[i])   //保证deque里面的sum是严格递增的 我们确定我们前面没有高个,有就踢他
                dq.pop_back();
                
            while(dq.size() > 0 && sum[i] - sum[dq.front()] >= k){  从最前面第一位同学开始,进行比较
                min_len = min(min_len, i - dq.front());
                dq.pop_front();
            }

            dq.push_back(i);  最后才坐下去


        }

        return min_len == INT_MAX? -1:min_len;



    }
};

在这里插入图片描述在这里插入图片描述

故题目意思为有几种i、j的组合,满足prefixSum[j] - prefixSum[i-1] = k;

  • 每个元素对应一个“前缀和”
  • 遍历数组,根据当前“前缀和”,在 map 中寻找「与之相减 == k」的历史前缀和
  • 当前“前缀和”与历史前缀和,差分出一个子数组,该历史前缀和出现过 c 次,等价于当前项找到 c 个子数组求和等于 k。
  • 遍历过程中,c 不断加给 count,最后返回 count
class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        unordered_map<int, int> mp;
        mp[0] = 1;   //即当i = -1时,prefixSum[-1] = 0;
        int cnt = 0, prefixSum = 0;

        for(int i = 0; i < nums.size(); i++){
            prefixSum += nums[i];

            if(mp[prefixSum - k]){
                cnt += mp[prefixSum - k];
            }

            if(mp[prefixSum])
                mp[prefixSum]++;
            else
                mp[prefixSum] = 1;
        }


        return cnt;


    }
};

在这里插入图片描述

class Solution {
public:
    int findMaxLength(vector<int>& nums) {
        unordered_map<int, int> mp;
        mp[0] = -1;
        int max_len = 0;
        int sum = 0;

        for(int j = 0; j < nums.size(); j++)
            if(nums[j] == 0)
                nums[j] = -1;

        for(int i = 0; i < nums.size(); i++){
            sum = sum + nums[i];

            if(mp.count(sum) != 0){
                int len = i - mp[sum];
                if(len > max_len)
                    max_len = len;
                //mp[sum] = i;
            }
            else{
                
                mp[sum] = i;
            }
        }

        return max_len;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值