1.题目介绍

给你一个整数数组 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

2.题解

请注意题目中要求的连续非空序列,要求1.连续 2.非空!!!

2.1 枚举(O(n^2))

思路

最简单的思路是利用双重循环确定数组的开头和结尾,在利用一重循环来进行遍历相加

int count = 0;
for (int start = 0; start <= nums.size(); start++)
{
for (int end = start; end <= nums.size(); end++)
{
int sum = 0;
for (int i = start; i <= end; i++)
sum += nums[i];
if (sum == k) count++;
}
}

但是这里的时间复杂度达到了O(n^3),必定会超过限制,所以我们进行了一些优化

还是双重循环遍历,确定数组的两个端点

但每次并非从前向后,而是从后向前挨个相加检查。

start确定遍历子数组的右端点,这里end为何不是从0开始,而是从start开始呢?

这样有一个什么好处呢,就是我们每次都有着[j,i]的和

只要再加上nums[j-1],就可以再得到[j-1,i]。

如果end从0开始,其实就和上面的三重循环遍历没有区别了

题解

注意这里找到 sum == k的时候,不可以直接break,因为举个例子[-1,1,0] k = 0; 这时候start指向0这个数,发现sum = k直接break,子数组[-1,1,0]也满足条件但是没有算上!!!

class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int count = 0;
for (int start = 0; start < nums.size(); start++) {
int sum = 0;
for (int end = start; end >= 0; end--) {
sum += nums[end];
if (sum == k) {
count++;
}
}
}
return count;
}
};

2.2 前缀和 + 哈希表优化

思路

关于前缀和是啥,请参考:前缀和

即 存在:preSum[i] = preSum[i-1] + nums[i]

前缀和 就是从 nums 数组中的第 0 位置开始,累加到第 i 位置的结果,我们常把这个结果保存到数组 preSum 中,记为 preSum[i]。

降二重循环为一重循环:

我们可以基于方法一利用数据结构进行进一步的优化,我们知道方法一的瓶颈在于对每个 i,我们需要枚举所有的 j 来判断是否符合条件,所以可以优化为一重循环吗?

我们既然选用一重循环,就面临一个问题,我们只能确定一个参数,这里我们肯定选择区间的右端点,这样的话我们怎么知道其与另一端点构成的子数组和呢?

这里我们利用前缀和的思路去做即可,即我们需要一个数组或者哈希表来保存之前求得的和,即[0,i-1]的和。

这里还有一个问题:子数组可能不是从下标0开始,也有可能是[j,i], 也就是 preSum[i] - preSum[j] = k;

那换个思路是不是我只要用哈希表存储了[0,i-1]每个0开始子数组{如[0,0],[0,1],[0,2]...}的前缀和和其出现次数,

并且加上一个用于表示[0,i]这个数组的键值对{0,1} [preSum[i] -preSum[0]表示的是[1,i],这里我必须加上这个键值对,preSum[i]-0表示的才是[0,i]的值]。

在得到preSum[i] = preSum[i-1] + nums[i]后,由preSum[i] - preSum[j] = k;演变为preSum[j] = preSum[i] - k; 寻找哈希表中值为preSum[i] - k的存在及其出现次数,若存在,将count加上出现次数;不存在,继续遍历即可。

但我们再仔细想想,已经使用了哈希表存储了前缀和及其出现次数,我们还需要用preSum数组来存储前缀和吗?明显是不需要的,我们只需要维护一个前缀和变量pre即可

这里不使用数组存储也是考虑到数组无法快速记录出现次数的问题

class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
unordered_map<int, int> mp;
int count = 0, pre = 0;
mp[0] = 1;
for (int i = 0; i < nums.size(); i++){
pre += nums[i];
if (mp.count(pre - k)) count += mp[pre-k];
mp[pre]++;
}
return count;
}
};

560.和为k的数组的更多相关文章

  1. 力扣 - 560. 和为K的子数组

    目录 题目 思路1(前缀和) 代码 复杂度分析 思路2(前缀和+哈希表优化) 代码 复杂度分析 题目 560. 和为K的子数组 思路1(前缀和) 构建前缀和数组,可以快速计算任意区间的和 注意:计算区 ...

  2. 【LeetCode】560. 和为K的子数组

    560. 和为K的子数组 知识点:数组:前缀和: 题目描述 给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数. 示例 输入:nums = [1,1,1], k = 2 ...

  3. Java实现 LeetCode 560 和为K的子数组(某著名排序大法改编)

    560. 和为K的子数组 给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数. 示例 1 : 输入:nums = [1,1,1], k = 2 输出: 2 , [1,1] ...

  4. 转:最小区间:k个有序的数组,找到最小区间使k个数组中每个数组至少有一个数在区间中

    转:http://www.itmian4.com/thread-6504-1-1.html 最小区间原题 k个有序的数组,找到最小的区间范围使得这k个数组中,每个数组至少有一个数字在这个区间范围内.比 ...

  5. Leetcode 560.和为k的子数组

    和为k的子数组 给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数. 示例 1 : 输入:nums = [1,1,1], k = 2 输出: 2 , [1,1] 与 [1 ...

  6. LeetCode 560. 和为K的子数组(Subarray Sum Equals K)

    题目描述 给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数. 示例 1 : 输入:nums = [1,1,1], k = 2 输出: 2 , [1,1] 与 [1,1] ...

  7. 560. 和为K的子数组

    Q: A: 1.暴力找所有可能的子数组,n^2个子数组,最长长度n,则n ^3. 2.n^2解法 从1~n-1各起点开始,一直找到结尾,n^2 class Solution { public: int ...

  8. LeetCode——560. 和为K的子数组

    给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数. 示例 1 : 输入:nums = [1,1,1], k = 2 输出: 2 , [1,1] 与 [1,1] 为两种不 ...

  9. 力扣题解-560. 和为K的子数组

    题目描述 给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数. 示例 1 : 输入:nums = [1,1,1], k = 2 输出: 2 , [1,1] 与 [1,1] ...

  10. 力扣Leetcode 560. 和为K的子数组

    和为K的子数组 给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数. 示例 : 输入:nums = [1,1,1], k = 2 输出: 2 , [1,1] 与 [1,1 ...

随机推荐

  1. 华企盾DSC邮件服务器测试连接提示Server has closed the connection(端口不对)

    解决方法:邮件服务器端口填错了,应该是smtp.126.com:s465,或者smtp.126.com:s587 其他邮箱同理.

  2. Spingboot整合Dubbo+zookeeper

    前言: 2023-12-26 19:38:05 最近学习分布式技术:Dubbo+zookeeper,准备写一个demo用springboot整合dubbo和zookeeper.但是看了网上一些教程都是 ...

  3. 谁再说学不会 MySQL 数据库,就把这个给他扔过去!

    大家好,我是民工哥. 又是新的一年奋斗路的开启,相信有不少人农历新年之后,肯定会有所变动(跳槽加薪少不了).所以,我把往期推送过的MySQL技术文章做了一个相关的整理,基础不好的可以从最基础的学习一遍 ...

  4. 用C实现HashTable

    简述HashTable的原理 HashTable是一种数据结构,通过key可以直接的到value,查找值时间总为常数级别O(1). 原理 HashTable底层是使用了数组实现的.数组只要知道了索引, ...

  5. Blazor入门100天 : 身份验证和授权之 OpenID 与 OAuth2

    目录: OpenID 与 OAuth2 基础知识 Blazor wasm Gitee 码云登录 Blazor wasm GitHub 登录 Blazor wasm Google 登录 Blazor w ...

  6. Docker 使用及常见问题总结

    一.使用 1.docker run -it 命令中的 it 参数是什么含义 在Docker中,-it是两个选项的组合,用于在交互式模式下运行容器.让我解释一下它们的含义: -i 或 --interac ...

  7. 文心一言 VS 讯飞星火 VS chatgpt (144)-- 算法导论12.1 4题

    四.用go语言,对于一棵有 n 个结点的树,请设计在 O(n)时间内完成的先序遍历算法和后序遍历算法. 我个人喜欢 灵小智 . 文心一言: 在 Go 语言中,我们可以使用递归来实现树的前序遍历和后序遍 ...

  8. HDC.Cloud2021|开发者们都在谈的云原生到底长什么样?

    摘要:云原生数据库基于存储与计算分离架构,与传统数据库相比,具备高性能.高扩展.一致性.易管理和多云支持等特性,在海量数据处理.智能存储.业务应用等方面表现出了强大的生命力. 近几年,云原生的风越刮越 ...

  9. HanLP — HMM隐马尔可夫模型 -- 预测

    https://www.bilibili.com/video/BV1aP4y147gA?p=8

  10. 【django-vue】七牛云上传视频 搜索接口 支付宝sdk二次封装 下单接口 前端支付页面 支付成功回调接口

    目录 上节回顾 课程详情接口 choice字段 今日内容 1 文件存储 1.1 七牛云上传文件 2 搜索导航栏 2.1 Header.vue 3 搜索接口 4 搜索页面 5 支付宝支付介绍 5.1 支 ...