【LeetCode】974. Subarray Sums Divisible by K 解题报告(C++)
作者: 负雪明烛
id: fuxuemingzhu
个人博客: http://fuxuemingzhu.cn/
题目地址:https://leetcode.com/problems/subarray-sums-divisible-by-k/
题目描述
Given an array A of integers, return the number of (contiguous, non-empty) subarrays that have a sum divisible by K.
Example 1:
Input: A = [4,5,0,-2,-3,1], K = 5
Output: 7
Explanation: There are 7 subarrays with a sum divisible by K = 5:
[4, 5, 0, -2, -3, 1], [5], [5, 0], [5, 0, -2, -3], [0], [0, -2, -3], [-2, -3]
Note:
- 1 <= A.length <= 30000
- -10000 <= A[i] <= 10000
- 2 <= K <= 10000
题目大意
在一个数组中有多少个连续子数组的和,恰好能被K整除。
解题方法
动态规划
定义DP数组,其中dp[i]代表以i结尾的能被K整除的子数组的最多个数。既然要求子数组的和,那么我们知道,肯定需要求数组累积和sums的。那么,对于sums每个位置i向前找,找到第一个差能被K整除的位置j,就停止即可。此时的dp[i] = dp[j] + 1. 题目要求的结果是sum(dp).
下面分析这个递推公式怎么来的。dp[j]表示以j位置结尾的子数组,该子数组的和能被K整除。那么当我们寻找到(sums[i] - sums[j]) % K == 0的时候,说明子数组sums[i, j]也能被K整除,那么,以i结尾的所有子数组个数等于以j结尾的子数组后面拼接上[i,j]子数组,加上[i,j]子数组.即dp[i] = dp[j] + 1。那么,为什么会break掉呢?这是因为,我们dp的状态是以i结尾的子数组的最大个数,再往前搜索则不是最大的。
这个代码的时间复杂度是O(N^2)的,也AC了,我认为主要是break的功劳。
c++代码如下:
class Solution {
public:
int subarraysDivByK(vector<int>& A, int K) {
const int N = A.size();
vector<int> sums = {0};
for (int a : A)
sums.push_back(a + sums.back());
vector<int> dp(N + 1, 0);
int res = 0;
for (int i = 1; i <= N; ++i) {
for (int j = i - 1; j >= 0; --j) {
if ((sums[i] - sums[j]) % K == 0) {
dp[i] = dp[j] + 1;
res += dp[i];
break;
}
}
}
return res;
}
};
前缀和求余
其实,在上面这个做法当中,我们对于每个i位置都向前去查询(sums[i] - sums[j]) % K == 0的j,找到之后立马break,这一步可以更加简化,只要我们使用前缀和,并且相同余数的和。
如果(sums[i] - sums[j]) % K == 0,说明sums[i]和sums[j]都是K的倍数,所以得出sums[i] % K == sums[j] % K。也就是说,我们找到sums[i] % K这个数字的之前的状态即可。根据上面的DP,我们知道只需要找到最后的这个结果,然后break掉的意思就是,我们只需要保存最后的状态。总之,我们需要维护一个hash_map,保存每个余数在每个位置前面,出现的次数。
刚开始时,m[0] = 1,即假设0的出现了1次。然后遍历每个数字,对前缀和+当前数字再求余,在C++里面由于负数求余得到的是负数,所以要把负余数+K才行。把字典中保存的之前的结果累计,就是结果。
想了很久为什么是加的当前数字之前的结果,而不是现在的结果?这是因为,我们当前再次遇到了这个数字,才能说明形成了一个同余的区间。所以加的永远是前面的余数存在了多少次。这样,当某个余数只出现了1次时,并不会计入到结果里。
class Solution {
public:
int subarraysDivByK(vector<int>& A, int K) {
unordered_map<int, int> m;
int preSum = 0;
int res = 0;
m[0] = 1;
for (int a : A) {
preSum = (preSum + a) % K;
if (preSum < 0) preSum += K;
res += m[preSum]++;
}
return res;
}
};
日期
2019 年 1 月 13 日 —— 时间太快了
【LeetCode】974. Subarray Sums Divisible by K 解题报告(C++)的更多相关文章
- Leetcode 974. Subarray Sums Divisible by K
前缀和(prefix sum/cumulative sum)的应用. 还用了一个知识点: a≡b(mod d) 则 a-b被d整除. 即:a与b对d同余,则a-b被d整除. class Solutio ...
- 【leetcode】974. Subarray Sums Divisible by K
题目如下: Given an array A of integers, return the number of (contiguous, non-empty) subarrays that have ...
- 974. Subarray Sums Divisible by K
Given an array A of integers, return the number of (contiguous, non-empty) subarrays that have a sum ...
- LC 974. Subarray Sums Divisible by K
Given an array A of integers, return the number of (contiguous, non-empty) subarrays that have a sum ...
- 「Leetcode」974. Subarray Sums Divisible by K(Java)
分析 这题场上前缀和都想出来了,然后就没有然后了...哭惹.jpg 前缀和相减能够得到任意一段连续区间的和,然后他们取余\(K\)看余数是否为0就能得到.这是朴素的遍历算法.那么反过来说,如果两个前缀 ...
- 119th LeetCode Weekly Contest Subarray Sums Divisible by K
Given an array A of integers, return the number of (contiguous, non-empty) subarrays that have a sum ...
- [Swift]LeetCode974. 和可被 K 整除的子数组 | Subarray Sums Divisible by K
Given an array A of integers, return the number of (contiguous, non-empty) subarrays that have a sum ...
- 【LeetCode】1022. Smallest Integer Divisible by K 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...
- 【LeetCode】713. Subarray Product Less Than K 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/subarray ...
随机推荐
- grep -r
今晚改脚本 我发现了一个很有趣的事情,一共56个配置文件 1 # 注意:对一些参数一致的多个文件可以用此方法 2 # grep -r 查找文件内容,其中PARALLEL=2就是我要替换的内容 3 4 ...
- 在 vscode.dev 中直接运行 Python !纯浏览器环境,无后端!
其实有挺长一段时间没有写自己的 VS Code 插件了! 还是要感谢我们 DevDiv 组的 Flexible Friday 活动,让我可以在工作日研究自己感兴趣的项目. Flexible Frida ...
- day19 进程管理
day19 进程管理 什么是进程,什么是线程 1.什么是程序 一般情况下,代码,安装包等全部都是应用程序 2.什么是进程 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进 ...
- 零基础学习java------23---------动态代理,ip,url案例
1. 动态代理 2. ip,url案例 给定的access.log是电信运营商的用户上网数据,第一个字段是时间, 第二个字段是ip地址,第三个字段是访问的网站,其他字段可以忽略不计. 第一个字段是网段 ...
- h5移动端设备像素比dpr介绍
首先介绍一下概念 devicePixelRatio其实指的是window.devicePixelRatio window.devicePixelRatio是设备上物理像素和设备独立像素(device- ...
- Set、Map、WeakSet 和 WeakMap 的区别
先总结: Set1. 成员不能重复2. 只有健值,没有健名,有点类似数组.3. 可以遍历,方法有add, delete,hasweakSet 1. 成员都是对象 2. 成员都是弱引用,随时可以消失. ...
- 安全相关,xss
XSS XSS,即 Cross Site Script,中译是跨站脚本攻击:其原本缩写是 CSS,但为了和层叠样式表(Cascading Style Sheet)有所区分,因而在安全领域叫做 XSS. ...
- Java SSLSocket
Java SSLSocket JSSE(Java Security Socket Extension)是Sun公司为了解决互联网信息安全传输提出的一个解决方案,它实现了SSL和TSL协议,包含了数据加 ...
- 4.1 python中调用rust程序
概述 使用rust-cpython将rust程序做为python模块调用: 通常为了提高python的性能: 参考 https://github.com/dgrunwald/rust-cpython ...
- java中的collection小结
Collection 来源于Java.util包,是非常实用常用的数据结构!!!!!字面意思就是容器.具体的继承实现关系如下图,先整体有个印象,再依次介绍各个部分的方法,注意事项,以及应用场景. ...