连续的子数组和--动态规划

leetcode 523

连续的子数组和

题目描述:给定一个包含非负数的数组和一个目标整数 k,编写一个函数来判断该数组是否含有连续的子数组,其大小至少为 2,总和为 k 的倍数,即总和为 n*k,其中 n 也是一个整数。

示例 1:

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

示例 2:

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

说明:

  • 数组的长度不会超过10,000。
  • 你可以认为所有数字总和在 32 位有符号整数范围内

解法1

思路:用两层for循环可以很简单的解决这个问题

bool checkSubarraySum(int* nums, int numsSize, int k)
{
    int i, j;
    long sum=0;
    for(i=0; i<numsSize; i++)
    {
        sum = nums[i];
        for(j=i+1; j<numsSize; j++)
        {
            sum+=nums[j];
            if(k)
            {
                if(sum%k==0)
                    return true;
            }    
            else if(!k && sum==0)
                return true;
        }
        
    } 
    return false;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NyHH1N1E-1590305037043)(https://s1.ax1x.com/2020/05/24/YzmJrn.png)]

时间复杂度为O(n^2)

解法2

思路:我们用一个数组存放前缀和,就是前面几项的和,那么什么情况下会有子数组相等呢?

其实后面的项如果可以被k整除,那么可以理解为后面的项减去前面的项就等于n*k,那么后面的项对k取余是不是就等于前面的项了,因为n*kk取余就为0了,那么是不是可以这样理解,只有我们发现有一个数组的两个前缀项的和对k取余相等,就表示有连续字串对k取余等于0?显然是这样的

现在问题就是,我们如何保存这些前缀项对k取余的值,并且它对应的下标,然后每当我们求出一个前缀项和时,就能跟前面的前缀项进行比较(两个前缀项对k取余是否相等),显然,我们可以通过哈希表来实现

哈希表要做什么?

扫描二维码关注公众号,回复: 11326029 查看本文章
  • 哈希表中保存前缀项的下标
  • 哈希表的索引值为前缀项对k取余的值

这样我们可以想象一下基本流程

  • 对nums数组遍历,然后求前缀值
  • 将这个前缀值对k取余(k!=0时),然后用其在哈希表搜索,如果发现哈希表不为-1,说明前面已经有一个前缀值的下标保存在哈希表中了,现在就是取出这个下标,跟当前下标相减,大于1表示两个数以上,这样就找到了连续子数组了,直接返回true就可以
  • 如果没找到,就将其插入哈希表中

完整代码

#define MAXN 10000
//哈希表插入函数
void HashInsert(int *HashMap, int key, int index)
{
    HashMap[key]=index;
}
//哈希表查找函数,取出下标
int HashContain(int *HashMap, int key)
{
    return HashMap[key];
}
bool checkSubarraySum(int* nums, int numsSize, int k)
{
    if(numsSize==1) //k==1直接返回
        return false;
    if(numsSize==2)  // 主要是处理两个0的情况
        if(k==0)
            if(nums[0]+nums[1]==0)
                return true;
            else
                return false;
    int i, index;
    long sum=0;
    int HashMap[MAXN];
    for(i=0; i<MAXN; i++) //哈希表初始化
        HashMap[i]=-1;
    for(i=0; i<numsSize; i++)
    {
        sum += nums[i]; //求前缀值
        if(k!=0)
            sum = sum%k; 
        index=HashContain(HashMap,sum);//找下标
        if(index!=-1)
        {
            if(i-index>1) //两个以上
                return true;
        }	
        else
            HashInsert(HashMap,sum,i);
    }
    if(sum==0) //完整数组也是一个子数组
        return true;
    return false;
}

Yzbb24.png

时间复杂度为O(n), 因为只需要遍历一遍数组

解释一下,我这个代码之所以比解法1还差主要是因为哈希表的长度太大,并且初始化花费了太多时间,当k=0时,直接以前缀值作为哈希表的下标导致了哈希表的长度太大,这个代码还有值得优化的地方,如k=0时,哈希表的索引还能在处理一下。

题目来源以及解法参考:

作者:LeetCode-Solution

链接:https://leetcode-cn.com/problems/count-square-submatrices-with-all-ones/solution/tong-ji-quan-wei-1-de-zheng-fang-xing-zi-ju-zhen-2/

来源:力扣(LeetCode)

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处

猜你喜欢

转载自blog.csdn.net/jump_into_zehe/article/details/106315599