【leetcode】袁厨精选题详解之和为K的子数组

题目描述:560和为K的子数组

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

示例 1 :

输入:nums = [1,1,1], k = 2
输出: 2 

说明: [1,1] 与 [1,1] 为两种不同的情况。

示例2:

输入:nums = [1,1,1,0], k = 2
输出: 3 

说明:[1,1],[1,1],[1,1,0]都是

示例3:

输入:nums = [-1,1,1,0], k = 2
输出: 2

说明:[1,1],[1,1,0]都是

题目要求很好理解,但是我们首先要考虑到所有会发生的情况,因为是int型数组,所以里面的整数类型无非就是小于零,等于0,大于零。所以我们做这个题目的时候需要重点考虑一种情况,那就是数组中包含0的情况,比如示例2,[1,1],[1,1,0]都为其子数组,不能漏掉这个情况。有些刚开始刷题的同学,可能想不到这种情况,而且原题示例里面只给了一个例子,所以某些特殊情况想不到,不过随着你刷题数目的增加,你分析题目的能力则会越来越强,拿到一个题首先就能想到其中的一些特殊例子。

首先我们先说一下暴力解法

注:暴力法我们比较容易想到的,但是暴力法的时间复杂度往往会比较高,虽然时间复杂度比较高,但是我们也一定不要忽略暴力解法(尤其是遇到没太有思路的题目)而且很多时候其他解法是对暴力法的优化,所以我们做题时候不要眼高手低,忽略暴力法。而是应该试着对暴力方法进行优化。

暴力法的思路很简单,就是双重循环,对nums[j]进行累加,当和为K值时,计数器加1。遍历结束后,返回数值。暴力方法对0存在的情况同样适用,因为sum+0,值仍为sum,如果此时sum等于k,则计数器仍会加一。

在这里插入图片描述

题目代码:

class Solution {
    
    
    public int subarraySum(int[] nums, int k) {
    
    
          if(nums.length == 0){
    
    
              return 0;
          }  
          //计数器
          int count = 0;
          //代表的是蓝指针的运动轨迹
          for(int i =0;i<nums.length;i++){
    
    
              int sum = 0;
              //代表橙指针的运动轨迹
              for(int j =i;j<nums.length;j++){
    
    
                  //将橙指针遍历的值进行相加
                  sum += nums[j];
                  //等于时计数器加1
                  if(sum == k){
    
    
                      count++;
                      //这里不可以break,因为可能有这种情况k=1数组为[1,0,0,1,-1]这个情况
                  }                  
              }
          }
          return count;
    }
}

Hashmap法:

这个方法比较巧妙,leetcode中有好几个题都可以使用这个方法,所以希望读者可以认真看下这个方法,可能刚开始刷题的时候看起来有些吃力,不过我们可以一起讨论。

我们来看一下sum的值的变化

sum[0]=nums[0];

sum[1]=nums[0]+nums[1];

sum[2]=nums[0]+nums[1]+nums[2];

sum[3]=nums[0]+nums[1]+nums[2]+nums[3];

因为sum[3]=sum[2]+nums[3],所以sum[3]-sum[2]=nums[3],sum[3]-sum[1]=nums[2]+nums[3];

通过上式我们知道了sum[j]-sum[i]=k,变形得sum[j]-k=sum[i];这个题目也就变成了求sum[i]的出现次数了。

在这里插入图片描述

在这里插入图片描述

class Solution {
    
           
    public int subarraySum(int[] nums, int k) {
    
    
        int count = 0;//计数器
        if(nums.length < 1){
    
    
            return 0;
        }
        //hashmap用来存sum[i]的和出现的次数
        HashMap<Integer, Integer> map = new HashMap<>();
        map.put(0,1);//防止这种情况,数组只有一个1,k=1则count=1
        int sum = 0;
        for(int i = 0; i<nums.length; i++){
    
    
           sum += nums[i];//累加
            //获取sum-k出现的个数,例当前指针在第j位。sum[j]=10,k=2,
            //则需要知道sum[i]=8时,共有几种情况,sum[i]代表的是前i位的值
           if(map.containsKey(sum - k)){
    
    
               count += map.get(sum-k);//获取次数
           }
           map.put(sum,map.getOrDefault(sum,0)+1);//没出现则存入一次
       }
       return count;
    }
    
}

猜你喜欢

转载自blog.csdn.net/tan45du_yuan/article/details/109297850