您的位置:首页 > 其它

【Leetcode】53. Maximum Subarray

2017-03-03 16:16 459 查看

Description:

Find the contiguous subarray within an array (containing at least one number) which has the largest sum.

Example:

Given the array [-2,1,-3,4,-1,2,1,-5,4],

the contiguous subarray [4,-1,2,1] has the largest sum = 6.

思路:

此题有多种解题思路。常规的解题方式,可以通过循环逐个比较连续的子数组(或者叫子序列)内元素的和的大小,以下是C++的实现方式

class Solution{
public:
int MaxSubArray(int *arr,int len,int left, int right){
int temp = 0;
int max = 0;
for(i=0;i<len;i++){
temp = 0;
for(j=i;j<len;j++){
temp += arr[j];
if(temp>max){
max = temp;
left = i;
right = j;
}
}
}
return max;
}

private:
int i,j,len;
int *arr;
int left,right;//数组的左右两端起末位置
};


但是这种方法的时间复杂度为O(n^2),对于数组元素个数较多的时候,效率会比较低。

我们可以仔细观察得到,循环比较逐个比较把所有可能的子序列都计算了一遍,但实际上不需要计算所有的子序列,如果有些子序列的开头和结尾是负数的话是无法得到和的最大值,因此可以只计算开头和结尾为正数的。更具体来说,开头是正数可以转换为这样一个问题:上一个元素的值a[i-1]与当前元素的值a[i]的和比当前元素的值a[i]要小,那么取当前元素的位置作为最大子序列的起始位置,否则保持不变。同样的,结尾为正数可以转化为:当前元素的值a[i]和下一个元素的值a[i+1]比当前元素大,那么下一个元素的位置作为最大子序列的结束位置,否则保持不变。这样,我们得到了一个递归的解决方式。

class Solution {
public:
int MaxSubArray(int *arr,int len){
int max_sum = arr[0];
int max_end_pos = arr[0];
int sum = 0;
left = 0;
right = 0;
for(int i=1;i<len;i++){
sum = max_end_pos + arr[i];
if(sum > arr[i]){
max_end_pos = sum;
}else{
max_end_pos = arr[i];
left = i;
}
if(max_sum<max_end_pos){
max_sum = max_end_pos;
right = i;
}
}
return max_sum;
}

private:
int i,j,len;
int *arr;
int left,right;
};


由此可见,该算法中只有一次循环,算法复杂度为O(n),拥有十分优异的效率。

除此之外,该问题还可以用分治法来解答。用分治法的时间复杂度为O(nlogn),比常规算法效率高。

class Solution{
public:
int MaxInThree(int a,int b,int c){
if(a>b) a = b;
if(a<c)
return c;
else
return a;
}
int MaxSubArray(int *arr,int left,int right){
int max_left_sum,max_right_sum;//左右两半部分最大的和
int sub_left_sum=0,sub_right_sum=0; //左子序列的和与右子序列的和
int max_sub_left_sum=0,max_sub_right_sum=0;//左子序列的最大和与右子序列的最大和
int mid;
//当只有一个元素的时候
if(left==right){
if(a[left]>0)
return a[left]
else
return 0;
}
//将数组分为两部分,分别求两部分的和的最大值
mid=(left+right)/2;
max_left_sum = MaxSubArray(arr,left,mid);
max_right_sum = MaxSubArray(arr,mid+1,right);

//在左半部分从中间到左侧进行子序列匹配
for(i=mid;i>=left;i--){
sub_left_sum+=arr[i];
if(sub_left_sum>max_sub_left_sum)
max_sub_left_sum = sub_left_sum;
}
//在右半部分从中间到右侧进行子序列匹配
for(i=mid+1;i<=right;i++){
sub_right_sum+=arr[i];
if(sub_right_sum>max_sub_right_sum)
max_sub_right_sum = sub_right_sum;
}
return MaxInThree(max_left_sum,max_right_sum,max_sub_left_sum+max_sub_right_sum);
}

private:
int i,j,len;
int *arr;
int left,right;
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: