子数组和为k&子数组和最大

题目1:子数组和为k

/*给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。

子数组是数组中元素的连续非空序列。



示例 1:

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

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


提示:

        1 <= nums.length <= 2 * 104
        -1000 <= nums[i] <= 1000
        -107 <= k <= 107*/

思路:

本来想用滑动窗口实现,但是实现后发现,该方法只对数组元素全部为正才能用,

题目中是整数数组,整数包括负整数和正整数和0,当有负整数时,和不是越加越大

所以不能使用滑动窗口实现

该问题是一个前缀和的典型问题

前缀和问题就是用 sum[i] - sum[j-1] 快速计算数组 [j ,i] 元素和的问题。详细来说,就是通过预处理计算出以第 0 个元素起始,到第 i 个元素结尾的元素之和,并将其记录为数组 sum[i],从而实现通过 sum[i] - sum[j-1] 快速计算 [j ,i] 位置的元素和,这样的问题就是前缀和问题。

例如[0,1,2,3,5,6,-1,-2],前缀和为[0,1,3,6,11,17,16,14]

那么上述问题可以改为sum[i]-sum[j-1]=k,再次转换可以转换为,sum[i]-k=sum[j-1]的问题

有多少个sum[j-1]=sum[i]-k,就是有多少个符合和为k的子数组

hashMap.put(sum,hashMap.getOrDefault(sum,0)+1)这行代码为什么要放到最后,

因为题目要求是连续子数组,所以j一定要比i小,如果放到上边,那么符和sum[i]-k=sum[j-1],的j肯定要多

子数组和为k&子数组和最大_第1张图片

   public static int getNumber(int[] nums ,int k){
//次数
       int count =0;
//和
       int sum=0;
//记录前缀和一样的前缀和数量
       HashMap hashMap = new HashMap<>();
       hashMap.put(0,1);//和为0的默认次数为1;
       for (int i = 0; i < nums.length; i++) {
           sum+=nums[i];//前缀和
           count+=hashMap.getOrDefault(sum-k,0);//当map中有符和条件的前缀和时,次数增加
//没有的话就是0
           hashMap.put(sum,hashMap.getOrDefault(sum,0)+1);//将前缀和相同的放入map,已经放入的就次数加1
       }
       return count;
   }

为什么要加 hashMap.put(0,1)

这个表示第0个元素的前缀和,如果不加的话,

如1,1,1 key 为2的情况,按照算法算出来次数是1

少了 前两个值和为2的这种场景,因为没有sum[1]-sum[0],sum[0] 是没有对应的值的

题目2:找出最大和的连续数组

/*    给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

    子数组 是数组中的一个连续部分。



    示例 1:
    输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
    输出:6
    解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
    示例 2:

    输入:nums = [1]
    输出:1
    示例 3:

    输入:nums = [5,4,-1,7,8]
    输出:23


    提示:

            1 <= nums.length <= 105
            -104 <= nums[i] <= 104
    进阶:如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。*/

思路1:

和最大,当前缀和确定后,如果想和最大,如果前缀和是正数,那么可以加上即将加入的数,加上之后的数,可能是比之前的最大和大,也可能比之前的最大和小,需要取最大的就行

如果前缀和是负数或0,那么前缀和就可以舍弃掉,从当前位置开始进行计算和,因为如果前缀和是负数或0,那么再加上一个正数,是会变大,但是也不会比这个正数大,比如前缀和是-3,下一个数是4,和为1,1也不会比4大,如果下一个数是负数,那么就会变小,也不会比当前值小,比如前缀和是-3,下一个数是-2,那么和为-5,肯定比-2要小,所以这时候,前缀和就相当于是累赘,直接舍弃掉就行,从当前位置开始计算和,才有可能是最大和

1、前缀和>0,前缀和加上当前值

2、前缀和<=0,舍弃前缀和,取当前值为前缀和

3、取前缀和与之前最大和之间的最大值

 public int  getMaxSum(int[] nums){
        int sum =0; 前缀和
        int res=0; 最大和
        for (int i = 0; i < nums.length; i++) {
            if(sum>0){ //前缀和>0
                sum+=nums[i]; //和加上当前值
            }else{ //否则,舍弃掉前缀和,并使用当前值当做前缀和
                sum=nums[i];//前边数的和是负数或0,直接将前边的和丢弃,因为前边为负,再加也肯定不是最大不如去掉
            }
            res= Math.max(res,sum); //取当前前缀和和最大值之间的大值
        }
        return res;
    }

你可能感兴趣的:(数据结构与算法基础,算法,数据结构,leetcode)