LeetCode 和为K的子数组

给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。

示例 1 :

输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。
说明 :

数组的长度为 [1, 20,000]。
数组中元素的范围是 [-1000, 1000] ,且整数 k 的范围是 [-1e7, 1e7]。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subarray-sum-equals-k

一开始想到的是滑动窗口的思路

public int subarraySum(int[] nums, int k) {
       int i,j = 0,sum = 0;
       int count = 0;
       for(i = 0; i < nums.length; i++){
           sum += nums[i];
           while(j < nums.length && sum >= k){
               if(sum == k)
                  count++;
               sum -= nums[j];
           }
       }
       return count;
    }

但是最后提交代码的时候会发现有错误,为什么呢?错误提示给出了一个测试用例[-1,-1,-1],k = -2,如果按照上面的例子来做的话,那么返回的是0,但是应该返回的是1.所以利用滑动窗口来实现的时候,必须要保证所有的数字都是正数才可以的,否则就会发生错误,因为题目中有说到元素的范围,所以会存在负数

暴力解决:

class Solution {
    public int subarraySum(int[] nums, int k) {
       int i,j,sum = 0;
       int count = 0;
       for(i = 0; i < nums.length; i++){
           sum = nums[i];
           if(sum == k)
              count++;
            /*
            考虑到元素是负数的情况,所以尽管当前元素等于了k,依旧需要考虑从这个元素开始的连续子数
            组的和是否为k
            */
           for(j = i + 1; j < nums.length; j++){
               sum += nums[j];
               if(sum == k)
                  count++;
           }
       }
       return count;
    }

}

运行结果:
在这里插入图片描述

方法二:前缀和 + 哈希表
前缀和pre[ i ] 表示的是以下标为0开始,下标 i 结尾的连续子数组和
所以假设 [ j , i ]是和为k的连续子数组的和,那么就会存在这样的关系:pre[ i ] - pre[ j - 1] = k。基于此,如果 i 结尾的连续子数组的和为k,主要取决于前缀和pre[ j - 1 ]有多少种情况,pre[ j - 1]有多少种情况,以 i 结尾的连续子数组和为 k 就有多少种情况。

所以我们就利用哈希表,其中对应的键是表示从0开始,i 结尾的连续子数组的和pre,对应的值表示pre存在的可能情况。

则有对应的代码:

class Solution {
     public int subarraySum(int[] nums, int k) {
       HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
       int i,pre = 0;//pre表示以从0开始,到下标为i结尾的连续子数组的和
       boolean flag;
       int count = 0;
       /*
       map.put(0,1)这一步是必要的,因为可能存在0开始,下标i结尾的连续和刚好是k
       例如例子[1,1,1],k = 2,那么如果没有这一步的话,最后返回的结果是1,但是实际应该
       是2,原因就是因为第二个1出现了错误,第二个1的时候,pre = 2,由于没有进行map.put(0,1)
       这一步,从而导致flag为false,所以就少了这一种情况,从而导致错误
       */
       map.put(0,1);
       for(i = 0; i < nums.length; i++){
           pre += nums[i];//获取以i结尾的连续和
           /*
           从0开始,i结尾的连续和,如果假设[j,i]是连续和为k的子数组,那么pre[i] - pre[j - 1] = k
           所以再直到以i结尾连续和子数组之和,要求连续和为k的
           */
           flag = map.containsKey(pre - k);
           if(flag){
               //以i结尾的连续和为k的子数组的个数主要取决于连续和为pre - k的连续子数组的所有可能
               count += map.get(pre - k);
           }
           //将当前i结尾的连续子数组的和压入到哈希表中,如果之前已经存在了,那么就原来基础上加1
           if(map.containsKey(pre))
              map.put(pre,map.get(pre) + 1);
           else
              map.put(pre,1);
       }
       return count;
    }
}

运行结果:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
请用C++解决这个leetcode的问题:2653. 滑动数组的美丽值 提示 中等 26 相关企业 给你一个长度为 n 的整数数组 nums ,请你求出每个长度为 k 的数组的 美丽值 。 一个数组的 美丽值 定义为:如果数组中第 x 小整数 是 负数 ,那么美丽值为第 x 小的数,否则美丽值为 0 。 请你返回一个包含 n - k + 1 个整数的数组,依次 表示数组中从第一个下标开始,每个长度为 k 的数组的 美丽值 。 数组指的是数组中一段连续 非空 的元素序列。 示例 1: 输入:nums = [1,-1,-3,-2,3], k = 3, x = 2 输出:[-1,-2,-2] 解释:总共有 3 个 k = 3 的数组。 第一个数组是 [1, -1, -3] ,第二小的数是负数 -1 。 第二个数组是 [-1, -3, -2] ,第二小的数是负数 -2 。 第三个数组是 [-3, -2, 3] ,第二小的数是负数 -2 。 示例 2: 输入:nums = [-1,-2,-3,-4,-5], k = 2, x = 2 输出:[-1,-2,-3,-4] 解释:总共有 4 个 k = 2 的数组。 [-1, -2] 中第二小的数是负数 -1 。 [-2, -3] 中第二小的数是负数 -2 。 [-3, -4] 中第二小的数是负数 -3 。 [-4, -5] 中第二小的数是负数 -4 。 示例 3: 输入:nums = [-3,1,2,-3,0,-3], k = 2, x = 1 输出:[-3,0,-3,-3,-3] 解释:总共有 5 个 k = 2 的数组。 [-3, 1] 中最小的数是负数 -3 。 [1, 2] 中最小的数不是负数,所以美丽值为 0 。 [2, -3] 中最小的数是负数 -3 。 [-3, 0] 中最小的数是负数 -3 。 [0, -3] 中最小的数是负数 -3 。 提示: n == nums.length 1 <= n <= 105 1 <= k <= n 1 <= x <= k -50 <= nums[i] <= 50
05-24

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值