hash+前缀和:和可被k整除的子数组

题目

给定一个整数数组 nums 和一个整数 k ,返回其中元素之和可被 k 整除的(连续、非空) 子数组 的数目。

子数组 是数组的 连续 部分。

示例 1:

复制代码
输入:nums = [4,5,0,-2,-3,1], k = 5
输出:7
解释:
有 7 个子数组满足其元素之和可被 k = 5 整除:
[4, 5, 0, -2, -3, 1], [5], [5, 0], [5, 0, -2, -3], [0], [0, -2, -3], [-2, -3]

示例 2:

复制代码
输入: nums = [5], k = 9
输出: 0

算法思路

经典的子数组问题,但仔细分析题目后发现无法使用滑动窗口,因为数组有正有负,其整体不具备单调性,所以只能考虑前缀和的方式来解决,但每加减一位都会引起数据和的增减性是不确定的,而且子数组并不一定是要从开头开始,所以不能完全使用前缀和来解决这个问题。

此时就要引入一个数学思想来将问题进行转化

假设如果两个数的差可以被k整除,也就是存在一个p被a和b的差所除后所得的商为k

此时a%p=a%p

证明如下:

因为数组中有负数的存在,而在C++中负数对正数取模结果依然是负数,而余数为负会干扰我们的判断,所以需要用下列方法将取模后的余数变为正数,此时是不影响取模后的结果的

因为要求子数组,所以问题可以转化为求第i位置之前,以i位置为结尾的有多少个子数组可以被k整除,假设把到i位置划分为两部分,前一部分和为x后一部分和为k的整数倍,那么可以推出公式 求(sum-x)%k=0的情况有多少中,而根据上面的同余定理进而可以转化为求满足i位置之前sum%k=x%k的情况有多少种,又考虑到可能有负数存在,所以需要对取模的值进行修正。

所以问题最终可以转化为:

代码实现

注意:此时不是真的要创建出一个前缀和表,因为只需判断在i之前是否存在满足条件的情况,所以只需在遍历时用哈希表进行记录,每次求和再去哈希表中查找是否有符合的情况即可。

cpp 复制代码
class Solution {
public:
    int subarraysDivByK(vector<int>& nums, int k) 
    {
        map<int,int> hash;
        hash[0]=1;
        int sum=0;
        int ret=0;
        for(auto e:nums)
        {
            sum+=e;
            int r=(sum%k+k)%k;
            if(hash.count(r)) ret+=hash[r];
            hash[r]++;
        }
        return ret;
    }
};
相关推荐
XUEYUAN5212几秒前
代理日志分析与监控:代理池健康状态巡检与分级告警体系搭建(运维实战)
运维·网络·网络协议·tcp/ip·算法·架构
sel_95 分钟前
【多轮对话论文导读(七)】多轮对话论文阅读笔记:从数据生成、用户模拟到上下文重构与长期记忆
论文阅读·人工智能·笔记·深度学习·算法·语言模型·自然语言处理
远游客07136 分钟前
为什么用「年×100+月」做比较
算法·gin
leavesleo1 小时前
DeepSeek 偷偷给你取外号?拆一下 AI 人格化背后的技术
算法
liliangcsdn1 小时前
skewness收益偏度取负因子背后逻辑的探索
人工智能·算法·机器学习
鹿角片ljp1 小时前
LeetCode 300. 最长递增子序列|从 DP O (n²) 到贪心 + 二分 O (n log n)
算法·动态规划
叠层归一研究院2 小时前
缝合维度:时空3+1结构的拓扑起源
人工智能·算法·机器学习·agi
YXXY3132 小时前
FloodFill算法
算法
OPEN-F2 小时前
C++入门教程:数组、字符串与指针入门
数据结构·c++·算法
pluviophile_s2 小时前
数据结构:第7讲:图
数据结构·笔记