题目的意思就是:在给定的数组中选取一组连续的子数组,使得这个子数组的和是所有子数组和最大值。
思路:
我首先想到的是算法导论分治策略一章给出的解法:
假设我们要寻找数组A[left,right]中的最大子数组,分治策略要求我们把问题分解两个规模相当的子数组,也就是说要找的子数组的中心middle,然后考虑求解两个子数组A1[left,middle],A2[middle+1,right]。求出的子数组肯定出自下面三种情景:
第三种情况下,子数组最好求,只需要在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),线性时间复杂度。
有了上述代码,最可以设计最大子数组的代码了:
代码分析:如果数组只含有一个元素,直接返回;
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);
}
};