Leetcode---523找出连续的子数组和

emmm,又是翻车的一天,以后做题要好好分析复杂度了,今天又超时了。。。
在这里插入图片描述

思路

前缀和好理解,之前已经说过很多次了,这次的重点是同余定理

假设存在满足条件的区间[i,j],即(s[j]-s[i]) %k==0,也就意味着(s[j]-s[i-1]) \ k=n(n是整数),设a=s[j]%k,x=s[j] \ k,b=s[i-1]%k,y=s[i-1]\k,则s[j] = x*k + a,s[i-1] = y*k + b,如果此时a=b,意味着s[j]-s[i-1]= x*k + a-(y*k + b)=(x-y)*k,其中x-y是整数
因此只要找到满足余数相同的s[j]和s[i-1]即可,其中j>=i+1

因此得到以下算法步骤:

  1. 先计算前缀和;
  2. 因为j>=i+1,时间复杂度又要求是线性的,所以借助Hashset辅助寻找满足条件的区间:每次枚举最右侧的值,如果set中存在和它相同余数的元素的话,则返回true。

代码

超时代码,因为数组的长度是10的5次方,所以时间复杂度只能是线性的 O ( n ) O(n) O(n),而下面使用前缀和的方法,因为嵌套循环,时间复杂度达到 O ( n 2 ) O(n^2) O(n2),所以会超时。

//超时代码
public boolean checkSubarraySum(int[] nums, int k) {
        int len = nums.length;
        System.out.println(len);
        if (len<2)
            return false;

        //前缀和
        int [] s = new int[len+1];
        for (int i=1;i<=len;++i)
            s[i] = s[i-1]+nums[i-1];
        //因为子数组的长度至少为2
        for(int i=2;i<=len;++i)
        {
            for (int j=0;j<i-1;++j)
            {
                System.out.println((s[j]-s[i])%k);
                if ((s[j]-s[i])%k == 0)
                    return true;
            }
        }

        return false;
    }

根据官方题解,使用同余定理,代码如下:

class Solution {
    public boolean checkSubarraySum(int[] nums, int k) {
        int len = nums.length;
        if (len<2)
            return false;

        //前缀和
        int [] s = new int[len+1];
        for (int i=1;i<=len;++i)
            s[i] = s[i-1]+nums[i-1];

        Set<Integer> set = new HashSet<>();
        for(int i=2;i<=len;++i)
        {
            set.add(s[i-2]%k);
            if (set.contains(s[i]%k))
                return true;
        }

        return false;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值