题目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肯定要多
public static int getNumber(int[] nums ,int k){
//次数
int count =0;
//和
int sum=0;
//记录前缀和一样的前缀和数量
HashMap<Integer,Integer> 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;
}
题目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;
}