分治法求最大子数组

求最大子数组:
一给定好的数组,在不改变起排列顺序的情况下,求非空的求和最大的子数组。
思路:把原数组分成两半,分别求两半的最大子数组,再求这两半合并后从中间往两边的最大子数组。然后把这三部分比较,得到整个的最大子数组。

即:1只取左边最大
2只取右边最大
3两边至少都包含一个的最大
(前提条件是得到的子数组是连续的,不能间段)

例子:先分,如图
在这里插入图片描述
再治:
在这里插入图片描述

上代码:

#include<iostream>
using namespace std;
#include<limits.h>

int max(int a, int b, int c)
{
	return a > (b > c ? b : c)?a:(b > c ? b : c);
}
int crossing_sub_array(int a[],int left,int mid,int right)
{
	int S_left = INT_FAST16_MIN;                         // 把由中向左求和初始值定义为负无穷
	int sum = 0;                                         // 临时储存求和变量

	//   跨区域求和是求left和right这个大区间内由中往两边的最大值,而不是全求和(全求和不一定是最大)

	// 求由中往左的最大
	for (int i = mid; i >= left; --i)
	{
		sum += a[i];                   // 直接在前面的基础上加,优化算法
		if (S_left < sum)
			S_left = sum;
	}

	int S_right = INT_FAST16_MIN;
	sum = 0;
	//  求由中往右的最大
	for (int i = mid + 1; i <= right; ++i)
	{
		sum += a[i];
		if (S_right < sum)
			S_right = sum;
	}
	// 即使S_right和S_left一正一负抵消变小也没关系,因为主递归函数已经把只取右边最大部分和只取左边最大部分都求好了,最后比较三个S取最大的就行
	int S3 = S_right + S_left;
	return S3;

}




int max_sub_array(int  a[], int left, int right)
{
	if (left == right)
		return a[left];                               //    如果只有一个元素,就是递归的出口
     
	int mid = (left + right) / 2;
	int S1 = max_sub_array(a, left, mid);             // 求左半部分的最大和
	int S2 = max_sub_array(a, mid + 1, right);        // 求右半部分的最大和
	int S3 = crossing_sub_array(a, left, mid, right); // 跨中间区域求最大和(中间两边都至少包含一个的情况)
	int S_max = max(S1, S2,S3);                       // 最大和是这三个中最大的
	return S_max;
}


int main()
{
	int array[7] = { 1,-2,4,5,-6,8,3, };
	double S=max_sub_array(array, 0, 6);
	cout << S << endl;
	return 0;
	
}
深度logn,每层遍历了n次,则时间复杂度O(nlogn)
  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值