[算法--前缀和] 和可以被K整除的子数组
目录
-
- 1. 要在暴力求解的思路上进行优化.
- 2. 我们该对暴力求解各种子数组情况如何分类?
- 3. 求解思路是: 前缀和 + 哈希表
- 4. **(b - a) % k == 0** -> 条件转换为 b % k == a % k(同余定理)
- 5. 哈希表的特性 与 CPP %号的特性
- 6. 强制修正可能的负号模运算结果: r = (sum % k + k) % k
- 7. 哈希表存什么?
- 8. 有没有可能余数是0?
接下来我们分享一下题目 -> 和可被K整除的子数组
好的, 我们直接开门见山, 最简单(我说思路上最简单, 效率可是最不"简单"的)的方法是暴力求解, 我相信大家都会操作, 这里也不再多说了~
1. 要在暴力求解的思路上进行优化.
这里选择的方式就是前缀和方法了, 至于怎么想到前缀和的? 因为有好几道类似的题目都是用前缀和进行优化效率的, 算是一种经验吧~
2. 我们该对暴力求解各种子数组情况如何分类?
所谓的"优化", 提升效率, 说白了就是少让计算机干活. 对于我们这道题来说就是让计算机直接避免掉一些一定不是最终结果的存在!
我们把以i位置为结尾的所有子数组看成一组, 这样的话方便进行操作~
3. 求解思路是: 前缀和 + 哈希表
我们以i位置为结尾的子数组抽象出下面模型来:
设i为数组中的任意位置, 用sum[i]标识[0, i]区间内所有元素的和.
想要知道有多少个以i位置为结尾的可以被k整除的子数组, 就需要找到多少个[0, x]的子数组之和等于sum[i], 说白了就是一种转换.
然而, 仅仅这样还不够, 因为我们暴力求解的效率是O(NN), 而这样一个一个去找[0, x]数组哪个之和为sum[i]的话时间复杂度也是O(NN), 所以还需要借助哈希表!
为了方便描述, 我们假设[0, x]之和为a, [x+1, i]数组之和为b, 那么我们可以得到假如说这是一个([x+1, i]数组)可以被k整除的话, 那么就满足: (b - a) % k == 0.
但是我们有个问题: 我们如何把"(b - a) % k == 0"转换为哈希表上去呢??? 如果是这样的话, 我们就不得不挨个试[0, ?]数组之和满足(b - a) % k == 0, 所以效率还是O(N * N)!
4. (b - a) % k == 0 -> 条件转换为 b % k == a % k(同余定理)
有个定理, 说如果 (b - a) % k == 0 ->b % k == a % k(同余定理).
具体证明如下:
原式左边: (a - b) ÷ p = k … 0
⇒ a - b = k * p (两边同时乘k)
⇒ a = b + k * p (b移项)
⇒ a % p = (b +