和为k的子数组
和为 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
问题分析:
一般看到数组中的连续子数组求和,我们会想到使用前缀和
解法:
前缀和
解题:
代码:
public static int subarraySum(int[] nums, int k) {
// 定义一个前缀和数组
int[] preNums = new int[nums.length+1];
// 前缀和数组的第一个值为0
preNums[0] = 0;
// 为前缀和数组赋值
for(int i = 1; i < preNums.length;i++){
preNums[i] = preNums[i-1] + nums[i-1];
}
int count = 0;
for(int left = 0;left < preNums.length;left++){
for(int right = left+1;right < preNums.length;right++){
if(preNums[right] - preNums[left] == k){
count += 1;
}
}
}
return count;
}
public static int subarraySum1(int[] nums,int k){
int count = 0,pre = 0;
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
map.put(0, 1);
for(int num : nums) {
pre += num;
if(map.containsKey(pre - k)) {
count += map.get(pre-k);
}
map.put(pre,map.getOrDefault(pre, 0)+1);
}
return count;
}
代码解析:
前面一个方法是单纯的前缀和方法,时间复杂度为O(N),我们定义了一个前缀和数组,其中的每一个数组元素都对应了原来数组的前n项和,接下来我们遍历前缀和数组。我们先固定数组的左边界,让左边不动,然后数组的右边节不断向右扩张,扩张一个,就将当前的值和k进行对比,如果相同,则count+1,不相同则右边界扩张。如果右边界到达了数组的末尾,将左边界右移一位,右边界回到左边界的起始位置,重新开始,知道左边界遍历到数组的末尾,最后得到的count就是和为k的子数组个数
第二个方法是对前缀和方法的优化,使用哈希表来帮助我们简化了求子数组和的过程。我们在遍历数组的时候,每一次都记录数组的前缀和,哈希表中以前缀和为key,前缀和出现的次数作为value存放数据。因为pre[j]-pre[i] = k,所以pre[i] = pre[j]-k,所以我们可以用当前前缀和-k的值代表此时有一个子数组的和为k,因此我们只需要判断哈希表中有没有pre[j]-k对应的数据就可以了,每一次遍历一个结点都要对哈希表进行更新。
总结:
前缀和的适用范围:在数组中,当我们要求连续数组的和的时候,我们就要考虑使用前缀和。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!