您的位置:首页 > 其它

523. Continuous Subarray Sum

2017-04-15 11:34 507 查看

一、题目简述

给定一个非负数组和目标整数K,写一个函数以检测给定数组中是否有一个长度至少为2的连续子序列,使得其和能够被K整除,即,其和为n∗K,n∈Z。

示例1

Input:[23,2,4,6,7],k=6

Output: True

Explanation: Because [2,4] is a continuous subarray of size 2 and sums up to 6.

示例2

Input: [23,2,6,4,7],k=6

Output: True

Explanation: Because [23,2,6,4,7] is an continuous subarray of size 5 and sums up to 42.

注意:

The length of the array won’t exceed 10,000.

You may assume the sum of all the numbers is in the range of a signed 32-bit integer.

函数原型:

bool checkSubarraySum(vector<int>& nums, int k)


二、编程思路

思路一:暴力求解

每个子序列的起始下标与终止下标均在[1,size]范围之内,其中size为序列num的长度。使用两重循环,列出序列nums中所有的子序列,求子序列之和sum,判断sum能否被K整除。

该方法的时间复杂度为O(n2),空间复杂度为O(1)。

思路二:动态规划

令f(s,l)表示序列nums中,下标从s开始,长度为l的子序列之和。

则有:

f(s,l)=nums[s],l=1;

f(s,l)=f(s,l−1)+nums[s],l>=2

使用一个二维数组记录各个子序列之和,如下图所示。

该方法的时间复杂度为O(n2),空间复杂度为O(n2)。时间与暴力法相同,而且更加浪费空间。

根据题中所给条件,序列最长为10000,则需要申请10000*10000的二维数组,运行时会报Memory Error。



思路三:动态规划二

在思路二中,可以发现每次只需二维数组中一列的数据,因此没有必要将整个数组保留下来。因此只申请一个长度为10000的数组,在每次操作时对其进行更新。记录从s开始长度为l的序列之和。

该方法的时间复杂度为O(n2),空间复杂度为O(n)。时间与暴力法相同,空间消耗相对可以接受,可以通过测试。



思路四:

参考网上大神时间复杂度为O(n)的实现。

原理:

对于序列a,若:

a[i]+a[i+1]+...+a[j]=n1K+q

a[i]+a[i+1]+...+a[j]+...+a[n]=n2K+q

则有:

a[j+1]+...+a[n]=(n2−n1)K

对于本题,求出从序列nums从0开始到end的子序列之和,记录其除以K的余数q,若有两个子序列余数相同,并且相应的end差值大于1,则说明所求子序列存在,否则便不存在。

该方法的时间复杂度为O(n),空间复杂度为O(1)。

三、程序设计

思路一:AC

class Solution {
public:
bool checkSubarraySum(vector<int>& nums, int k) {
int size=nums.size();
if(!size) return false;
int vsum = accumulate(nums.begin() , nums.end(),0);
if(k==0 && vsum==0 && size>1) return true;
if(k==0) return false;
for(int i=0;i<size;i++){
int sum=nums[i];
for(int j=i+1;j<size;j++){
sum+=nums[j];
if(sum%k==0){
// cout<<i<<" "<<j<<endl;
return true;
}
}
}
return false;
}
};


思路二:ME

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_SIZE 10000
int sum[MAX_SIZE][MAX_SIZE]={-1};

class Solution {
public:
bool checkSubarraySum(vector<int>& nums, int k) {
//special condation
int size=nums.size();
if(!size) return false;
int vsum = accumulate(nums.begin() , nums.end(),0);
if(k==0 && vsum==0 && size>1) return true;
if(k==0) return false;
//general condation
memset(sum,0,sizeof(int)*MAX_SIZE*MAX_SIZE);
for(int i=0;i<size;i++){
sum[i][0]=nums[i];
}
for(int len=2;len<=size;len++){
for(int start=0;start<size;start++){
if(start+len-1>=size) continue;
if(sum[start][len-1]<=0){
sum[start][len-1]=sum[start][len-2]+nums[start+len-1];
}
if(sum[start][len-1]%k==0){
//cout<<start<<" "<<len<<endl;
return true;
}
}
}
return false;
}
};


思路三:AC

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_SIZE 10000
int sum[MAX_SIZE]={-1};

class Solution {
public:
bool checkSubarraySum(vector<int>& nums, int k) {
//special condation
int size=nums.size();
if(!size) return false;
int vsum = accumulate(nums.begin() , nums.end(),0);
if(k==0 && vsum==0 && size>1) return true;
if(k==0) return false;
//general condation
memset(sum,0,sizeof(int)*MAX_SIZE);
for(int i=0;i<size;i++){
sum[i]=nums[i];
}
for(int len=2;len<=size;len++){
for(int start=0;start<size;start++){
if(start+len-1>=size) continue;
sum[start]=sum[start]+nums[start+len-1];
if(sum[start]%k==0){
return true;
}
}
}
return false;
}
};


思路四:AC

class Solution {
public:
bool checkSubarraySum(vector<int>& nums, int k) {
map<int,int> m;
map<int,int>::iterator it=m.end();

int sum=0;
m[0]=-1;
for(int i=0;i<nums.size();i++){
sum+=nums[i];

if(k)
sum%=k;

it=m.find(sum);
if(it!=m.end()){
if(i-it->second > 1){
return true;
}
}else{
m[sum]=i;
}
}
return false;
}
};


四、实验心得

动态规划在查找有很多重叠子问题的情况的最优解时有效。它将问题重新组合成子问题。为了避免多次解决这些子问题,它们的结果都逐渐被计算并被保存,从简单的问题直到整个问题都被解决。因此,动态规划保存递归时的结果,因而不会在解决同样的问题时花费时间。

动态规划只能应用于有最优子结构的问题。最优子结构的意思是局部最优解能决定全局最优解(对有些问题这个要求并不能完全满足,故有时需要引入一定的近似)。简单地说,问题能够分解成子问题来解决。

适用情况:

最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质(即满足最优化原理)。最优子结构性质为动态规划算法解决问题提供了重要线索。

无后效性。即子问题的解一旦确定,就不再改变,不受在这之后、包含它的更大的问题的求解决策影响。

子问题重叠性质。子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。

参考资料:动态规划
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息