【LeetCode】523. 连续的子数组和

409 阅读2分钟

连续的子数组和

给你一个整数数组 nums 和一个整数 k ,编写一个函数来判断该数组是否含有同时满足下述条件的连续子数组:

  • 子数组大小至少为 2,且
  • 子数组元素总和为 k 的倍数。 如果存在,返回 true;否则,返回false 。

如果存在一个整数 n ,令整数 x 符合 x = n * k ,则称x是k的一个倍数。0 始终视为k的一个倍数。

示例1

输入:nums = [23,2,4,6,7], k = 6
输出:true
解释:[2,4]是一个大小为2的子数组,并且和为6。

示例2

输入:nums = [23,2,6,4,7], k = 6
输出:true
解释:[23, 2, 6, 4, 7] 是大小为 5 的子数组,并且和为 42 。 
42 是 6 的倍数,因为 42 = 7 * 67 是一个整数。

思路

  • 题目中说:连续子数组和,很自然的想到了前缀和来求解。nums[i]=dp[i+1]-dp[i],求某一连续的序列和的话也如此。比如:计算
计算nums[i]到nums[j]之间的序列和=dp[j+1]-dp[i]
  • 同余定理:如果两个数a,b对k的余数相等,则两个数之间的差(a-b)可以被k整除。
  • 因此,本题中使用map+前缀和的思想求解。假设两个下标i,j+1的前缀和分别为dp[i],dp[j+1],如果他们对k的余数相等,则说明数组nums从下标i到j的连续数组和可以被k整除。
  • 定义一个map存放结果,其中key为余数,value为索引。

解法

func checkSubarraySum(nums []int, k int) bool {
    hashMap:=make(map[int]int,len(nums))
    hashMap[0]=-1
    remainder:=0
    dp:=make([]int,len(nums)+1)
    for i:=0;i<len(nums);i++{
        dp[i+1]=dp[i]+nums[i]
    }
    for i:=0;i<len(nums);i++{
        remainder=(dp[i+1])%k
        if index,ok:=hashMap[remainder];ok{
            if i-index>=2{
                return true
            }
        }else{
            hashMap[remainder]=i
        }
    }
    return false
}