题目:已知整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和以及子数组的区间,
示例:
输入:nums = [13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7]
输出:(7,10,43)
解释:最大子数组为[18,20,-7,12],索引为nums[7]~nums[10],和为43
分治思想:
任何连续子数组nums[i...j]一定是一下三种情况之一:
- 完全位于子数组nums[low,mid]
- 完全位于子数组nums[mid+1,high]
- 跨越了中间点mid,既i<=mid<j
第一步,先解决跨越中间点mid的情况
FIND_MAX_CROSSING_SUBARRAY(A,low,mid,high):
- left_sum =
- sum = 0
- for i = mid downto low
- sum = sum + A[i]
- if sum > left_sum
- left_sum = sum
- max_left = i
- right_sum =
- sum = 0
- for j = mid+1 to high
- sum = sum + A[j]
- if sum > right_sum
- right_sum = sum
- max_left = j
- return (max_left,max_right,left_sum + right_sum)
第二步,构造递归函数
FIND_MAX_SUBARRAY(A,low,high):
- if high == low
- return (low,right,A[low])
- else
- mid = (low + high) / 2
- (left_low,left_high,left_sum) = FIND_MAX_SUBARRAY(A,low,mid)
- (right_low,right_high,right_sum) = FIND_MAX_SUBARRAY(A,mid+1,high)
- (cross_low,cross_high,cross_sum) = FIND_MAX_CROSSING_SUBARRAY(A,low,mid,high)
- if(left_sum >= right_sum && left_sum >= cross_sum)
- return(left_low,left_high,left_sum)
- else if((right_sum >= left_sum&& right_sum >= cross_sum)
- return (right_low,right_high,right_sum)
- else
- return (cross_low,cross_high,cross_sum)
#include<stdio.h>
#include<stdlib.h>
#define N 16
typedef struct _Node
{
int left;
int right;
int sum;
}Node;//返回的数据类型
int Diff[N] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
int main() //ZCR: fighting
{
Node* Find_Max_Crossing_Subarray(int* A,int low,int mid,int high);//函数声明,必须,因为函数的定义在main函数下方
Node* Find_Max_Subarray(int* A,int low,int high);//函数声明
Node* ptr;//定义指针接受递归结束返回的最大子数组的左索引,右索引 以及 和
ptr = Find_Max_Subarray(Diff,0,15);
if(!prt)
{
printf("动态内存申请失败!!");
return 0;
}
printf("(%d,%d,%d)",ptr->left,ptr->right,ptr->sum);
free(ptr);//函数内部用了malloc,一定要释放内存,不然会造成内存泄漏
ptr = NULL;//良好编程习惯,别让它成为野指针,指向NULL就不是野指针的
return 0;
}
Node* Find_Max_Crossing_Subarray(int* A,int low,int mid,int high)
{
int left_sum = -100000, right_sum = -100000;
int i,max_left,max_right;
Node* s = (Node*)malloc(sizeof(Node));
if(!s)
{
printf("动态内存申请失败!!");
return NULL; //申请动态内存失败,直接返回
}
int temp = 0;
for(i = mid;i >= low;i--)
{
temp += A[i];
if(temp > left_sum)
{
left_sum = temp;
max_left = i;
}
}
temp = 0;
for(i = mid + 1;i <= high;i++)
{
temp += A[i];
if(temp > right_sum)
{
right_sum = temp;
max_right = i;
}
}
s->left = max_left;
s->right = max_right;
s->sum = left_sum + right_sum;
return s;
}
Node* Find_Max_Subarray(int* A,int low,int high)
{
Node *l,*r,*c,*d;//l=left,r=right,c=cross,d=done
int mid;
if(low == high)
{
d = (Node*)malloc(sizeof(Node));
if(!d)
{
printf("动态内存申请失败!!");
return NULL;
}
d->left = low;
d->right = high;
d->sum = A[low];
return d;
}
else
{
mid = (low + high) / 2;
l = Find_Max_Subarray(A,low,mid);
r = Find_Max_Subarray(A,mid+1,high);
c = Find_Max_Crossing_Subarray(A,low,mid,high);
if((l->sum >= r->sum) && (l->sum >= c->sum))
{
free(r);r = NULL;
free(c);c = NULL;
return l;
}
else if((c->sum >= l->sum) && (c->sum >= r->sum))
{
free(l);l = NULL;
free(r);r = NULL;
return c;
}
else
{
free(l);l = NULL;
free(c);c = NULL;
return r;
}
}
}