首页 > 其他分享 >LeetCode 974. 和可被 K 整除的子数组

LeetCode 974. 和可被 K 整除的子数组

时间:2024-07-08 16:28:17浏览次数:20  
标签:974 nums int sum presum record 数组 整除 LeetCode

974. 和可被 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

提示:

  • 1 <= nums.length <= 3 * 10^4
  • -10^4 <= nums[i] <= 10^4
  • 2 <= k <= 10^4

解法:前缀和 + 哈希表

通常,涉及连续子数组问题的时候,我们使用前缀和来解决。

我们令 P[i]=nums[0]+nums[1]+…+nums[i]。那么每个连续子数组的和 sum(i,j) 就可以写成 P[j]−P[i−1](其中 0<i<j)的形式。此时,判断子数组的和能否被 k 整除就等价于判断 (P[j]−P[i−1])modk==0,根据 同余定理,只要 P[j]modk==P[i−1]modk,就可以保证上面的等式成立。

因此我们可以考虑对数组进行遍历,在遍历同时统计答案。当我们遍历到第 i 个元素时,我们统计以 i 结尾的符合条件的子数组个数。我们可以维护一个以前缀和模 k 的值为键,出现次数为值的哈希表 record,在遍历的同时进行更新。这样在计算以 i 结尾的符合条件的子数组个数时,根据上面的分析,答案即为 [0..i−1] 中前缀和模 k 也为 P[i]modk 的位置个数,即 record[P[i]modk]。

最后的答案即为以每一个位置为数尾的符合条件的子数组个数之和。需要注意的一个边界条件是,我们需要对哈希表初始化,记录 record[0]=1,这样就考虑了前缀和本身被 k 整除的情况。

注意:不同的语言负数取模的值不一定相同,有的语言为负数,对于这种情况需要特殊处理。

哈希表使用长度为 k 的数组实现。

我们利用前缀和数组来求解问题,对于子数组 nums[i:j] (包含下标 i, j),其区间和为 sum[j]−sum[i - 1] (其中 sum 为预处理得到的前缀和数组),

我们要判断的是 (sum[j]−sum[i - 1])%K是否等于 0。
根据 mod 运算的性质,我们知道 (sum[j]−sum[i - 1])%K=sum[j]%K−sum[i - 1]%K。
故若想 (sum[j]−sum[i - 1])%K=0 ,则必有 sum[j]%K=sum[i - 1]%K。
所有满足 nums[i:j] 中元素之和可以被 K 整除的开始下标 i,必有 sum[j]%K=sum[i - 1]%K。我们以 sum[i - 1]%K 作为键值统计其出现的频率,从而对于每个下标 j 我们可以立即获得能和它组成满足要求的子数组的开始下标 i 的数量。
生成前缀和数组的过程中,将 key=sum[j]%k 出现的频率加入结果数组, 同时将 key=sum[j]%k 的出现频率加 1。
由于数组中有可能出现负数,我们需要将其加 K 从而使其 %K 之后的值为正数。

Java版:

class Solution {
    public int subarraysDivByK(int[] nums, int k) {
        int ans = 0;
        int[] record = new int[k];
        record[0] = 1;
        int presum = 0;
        for (int num: nums) {
            presum += num;
            int key = (presum % k + k) % k;
            ans += record[key];
            record[key]++;
        }
        return ans;
    }
}

Python3版:

class Solution:
    def subarraysDivByK(self, nums: List[int], k: int) -> int:
        ans = 0
        record = [0] * k 
        record[0] = 1
        presum = 0
        for num in nums:
            presum += num
            presum = (presum % k + k) % k 
            ans += record[presum]
            record[presum] += 1
        return ans

复杂度分析

  • 时间复杂度:O(n),其中 n 是数组 nums 的长度。我们只需要从前往后遍历一次数组,在遍历数组的过程中,维护哈希表的各个操作均为 O(1),因此总时间复杂度为 O(n)。
  • 空间复杂度:O(k),即 record数组 需要的空间。

标签:974,nums,int,sum,presum,record,数组,整除,LeetCode
From: https://blog.csdn.net/m0_56090828/article/details/140263836

相关文章

  • [LeetCode] 134. Gas Station
    想到了提前判断和小于0的情况,懒得写,果然被阴间用例10万个加油站坑了。classSolution:defcanCompleteCircuit(self,gas:List[int],cost:List[int])->int:#1n=len(gas)ifn==1:ifgas[0]>=cost[0]:ret......
  • LeetCode 算法:岛屿数量 c++
    原题链接......
  • [LeetCode] 238. Product of Array Except Self
    坑真的很多,首先要处理全零reduce没有值typeerror的问题。classSolution:defproductExceptSelf(self,nums:List[int])->List[int]:total=reduce(mul,nums)ret=[]iftotal==0:try:total=reduce(mul,[......
  • 刷爆leetcode第九期
    题目一单值二叉树如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。只有给定的树是单值二叉树时,才返回true;否则返回false。题目图片如下我们这里主要是判断下根的值和它的左孩子还有右孩子相不相等如果相等返回true如果不相等返回false(当然这里还需要......
  • 刷爆leetcode第十期
    题目一相同的树给你两棵二叉树的根节点p和q,编写一个函数来检验这两棵树是否相同。如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。首先我们要来判断下它们的根是否相等根相等的话是否它们的左子树相等是否它们的右子树相等一直到子树为空为止大......
  • Leetcode刷题记录1 哈希+双指针+滑动窗口
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言hot1001.哈希#1.两数之和#49.字母异位词分组#128.最长连续序列2.双指针#283.移动零#11.盛最多水的容器#15.三数之和#42.接雨水3.滑动窗口#3.无重复字符的最长子串#438.找到字符串中所有......
  • 打印100以内所有能被3整除的数,每5个数打印一行(devC++)
     今天让我们来学习如何利用C语言,在运行框中打印100以内所有能被3整除的数,每五个数打印一行。 首先,我们需要定义两个变量,其中n表示1~100的数字,m表示3的倍数的个数。然后利用一个for循环,在循环中n自增,利用一个if判断语句判断是否为3的倍数,如果是,则输出在循环中再利用一个......
  • [Leetcode]经典算法
    检测环快慢指针法是一种用于检测链表中是否存在环的有效方法,同时也可以找到环的起点。该方法的原理基于两个指针在链表上同时移动,其中一个移动得更快,而另一个移动得更慢。检测环的存在:使用两个指针,一个称为快指针(fast),一个称为慢指针(slow)。在每一步中,快指针向前移动两步,而慢......
  • leetcode678:有效的括号字符串
    给你一个只包含三种字符的字符串,支持的字符类型分别是 '('、')' 和 '*'。请你检验这个字符串是否为有效字符串,如果是 有效 字符串返回 true 。有效 字符串符合如下规则:任何左括号 '(' 必须有相应的右括号 ')'。任何右括号 ')' 必须有相应的左括号 '(' 。左括......
  • 【LeetCode 0024】【链表】交换单链表相邻两个节点
    SwapNodesinPairsGivena linkedlist,swapeverytwoadjacentnodesandreturnitshead.Youmustsolvetheproblemwithout modifyingthevaluesinthelist’snodes(i.e.,onlynodesthemselvesmaybechanged.)Example1:**Input:**head=[1,2,3......