您的位置:首页 > 其它

leetcode题解——53. Maximum Subarray

2016-11-11 18:42 375 查看


题目的意思就是:在给定的数组中选取一组连续的子数组,使得这个子数组的和是所有子数组和最大值。

解法一(分治策略)

思路:

我首先想到的是算法导论分治策略一章给出的解法:
假设我们要寻找数组A[left,right]中的最大子数组,分治策略要求我们把问题分解两个规模相当的子数组,也就是说要找的子数组的中心middle,然后考虑求解两个子数组A1[left,middle],A2[middle+1,right]。求出的子数组肯定出自下面三种情景:


子数组完全位于middle左侧

子数组完全位于middle右侧

子数组跨越了middle



第三种情况下,子数组最好求,只需要在middle左侧开始找到连续和最大子数组L,在middle右侧开始找到连续和最大子数组R,两个数组合并就可以得到跨越middle最大的子数组。

代码

str_array 结构体是用来存储最大子数组的区间和最大值;

find_Max_Crossing_Array()函数:因为寻找数组必须从middle开始,所以两个for循环均从middle开始,分别向左右查找。找到最大数组就更新索引和最大和,直到到达数组的两边。

typedef struct arra{
int left_;
int right_;
int sum_;
}str_array;

str_array find_Max_Crossing_Array(int *a, int left, int middle, int right) {
int left_sum_max = INT_MIN;
int right_sum_max = INT_MIN;
int max_left = 0;
int max_right = 0;
int sum = 0;
str_array tmp;

for (int i = middle; i >= left; i--) {
sum += *(a + i);
if (sum >= left_sum_max) {
left_sum_max = sum;
max_left = i;
}
}
sum = 0;
for (int i = middle+1; i <= right; i++) {
sum += *(a + i);
if (sum >= right_sum_max) {
right_sum_max = sum;
max_right = i;
}

}
tmp.left_ = max_left;
tmp.right_ = max_right;
tmp.sum_ = left_sum_max + right_sum_max;
return tmp;
}


算法复杂度,两个for循环都是遍历了整个数组,所以复杂度为O(n),线性时间复杂度。


有了上述代码,最可以设计最大子数组的代码了:

代码分析:如果数组只含有一个元素,直接返回;

如果数组只含有一个元素,直接返回

将数组分解,分别求解三种情况下的最大数组,各数组信息用left_array, right_array, acrossing_array保存

通过比较left_array.sum_,right_array.sum_,acrossing_array.sum_,选出这三个数组中和最大的数组

str_array find_Max_Sum_Child_Array(int *a, int left, int right) {
str_array tmp;
if (left == right) {
tmp.left_ = left;
tmp.right_ = right;
tmp.sum_ = *(a + left);
return tmp;
}
else {
int middle = (left + right) / 2;
str_array left_array, right_array, acrossing_array;
left_array = find_Max_Sum_Child_Array(a, left, middle);
right_array = find_Max_Sum_Child_Array(a, middle + 1, right);
acrossing_array = find_Max_Crossing_Array(a, left, middle, right);

if (left_array.sum_ >= right_array.sum_ && left_array.sum_ >= acrossing_array.sum_)
return left_array;
else if (right_array.sum_ >= left_array.sum_ && right_array.sum_ >= acrossing_array.sum_)
return right_array;
else return acrossing_array;
}
}


算法复杂度:递归结果调用了递归树,树的高度h=lgn,

复杂度T(n)=n*lgn;

下面是主函数,可以方便的获取最大子数组索引和sum:

int main() {
int a[9] = { -2,1,-3,4,-1,2,1,-5,4 };
str_array result = find_Max_Sum_Child_Array(a, 0, 8);
cout << result.left_ << " " << result.right_ << " " << result.sum_ << endl;
system("pause");
return 0;
}


运行结果:



问题差不多,所以在提交的时候基本上就是原来思路:

class Solution {
int divide(vector<int>& nums,int l,int r){
if(l==r)    return nums[l];

int m=(l+r)/2;
int left=divide(nums,l,m);
int right=divide(nums,m+1,r);
int middle=nums[m];
int tmp=middle;
for(int i=m-1;i>=l;i--){
tmp+=nums[i];
middle=max(middle,tmp);
}
tmp=middle;
for(int i=m+1;i<=r;i++){
tmp+=nums[i];
middle=max(middle,tmp);
}
return max(middle,max(left,right));

}
public:
int maxSubArray(vector<int>& nums) {
return  divide(nums,0,nums.size()-1);
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: