分治算法求解最大连续子数组

分治策略求解最大连续子数组问题:

原理:如果想要通过递归进行实现,就必须将数组进行子数组的划分,通过子数组划分,出现三种情况可能包含最大子数组,一种是在左边的子数组,一种是在右边的子数组,另一种是跨越中间量的子数组,对于左右子数组便又变成了求解其最大子数组(递归),而跨越中间的子数组需要单独进行遍历求取最大子数组

一直存在理解上的疑惑:如何确定递归得到的就是最大子数组?

通过正向进行递归计算如下:

假定存在如下数组,下列的步骤为依次进行递归的情况:

A1

A2

A3

A4

A5

A6

A7

A8

A9

A10

A11

A12

A13

A14

A15

A16

13

-3

-25

20

-3

-16

-23

18

20

-7

12

-5

-22

15

-4

7

A,1,16

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

A,1,8

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

A,1,4

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

A,1,2

1,1,A1

13

 

 

 

 

 

 

 

 

 

 

 

 

 

A,3,4

4,4,A4

20

 

 

 

 

 

 

 

 

 

 

 

 

 

A,1,2,4

1,4,7

10

 

 

 

 

 

 

 

 

 

 

 

 

A,5,8

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

A,5,6

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

A,7,8

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

A,5,6,8

 

 

 

 

 

 

 

 

 

 

 

 

 

 

A,1,4,8

 

 

 

 

 

 

 

 

 

 

 

 

 

从上表的递归情况进行分析:

最小子数组里面已经比较得到了最大连续的子数组,比如(A,1,2)  (A,3,4)  (A,1,2,4)中已经获取到最大数组,其作为A1,8的子数组左半边已经获取到最大子数组(可能为(A1,4)跨越中点的,也可能其他半边),而(A,1,4,8)只需要再进行跨越中点的子数组获取最大就可以和前面已经得到的结果即(A1,4)  (A,5,8)进行对比,然后再跟跨越8的中点的最大子数组对比,就能得到结果了

这样理解后,从正面也想通了分治策略用递归实现的原理。a,1,16->  (a,1,8) and (a,9,16) and (a 1,8,16)中取最大连续子数组,再进行递归

Java实现分治求解最大连续子数组:

public class MaxContinuousArray {

	public static int[] getMaxConArray(int left,int right,int[] arr){
		int mid = (left+right)/2;
		if(left==right){
			return new int[]{left,right,arr[left]};

		}
		int[] leftMaxValue=new int[2];
		int[] rightMaxValue=new int[2];
		int[] midMaxValue=new int[2];
		
		leftMaxValue=getMaxConArray(left, mid, arr);
		rightMaxValue=getMaxConArray(mid+1, right, arr);
		midMaxValue=getMidConArray(left, right, mid, arr);

		if(leftMaxValue[2]>rightMaxValue[2]&&leftMaxValue[2]>midMaxValue[2]){
			return leftMaxValue;
		}else{
			if(rightMaxValue[2]>midMaxValue[2]){
				return rightMaxValue;
			}else{
				return midMaxValue;
			}
		}
	}
	
	private static int[] getMidConArray(int left,int right,int mid,int[] arr){
		int leftSubMaxValue=0;
		int leftSubMaxInd=mid;
		int leftSubSum=0;
		
		int rightSubMaxValue=0;
		int rightSubMaxInd=mid;
		int rightSubSum=0;
		for(int i=1;i<mid-left+1;i++){
			leftSubSum+=arr[mid-i];
			if(leftSubMaxValue<leftSubSum){
				leftSubMaxValue=leftSubSum;
				leftSubMaxInd=mid-i;
			}
		}
		for(int i=1;i<right-mid+1;i++){
			rightSubSum+=arr[mid+i];
			if(rightSubMaxValue<rightSubSum){
				rightSubMaxValue=rightSubSum;
				rightSubMaxInd=mid+i;
			}
		}
		return new int[]{leftSubMaxInd,rightSubMaxInd,leftSubMaxValue+rightSubMaxValue+arr[mid]};
	}
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分治算法的基本思路是将问题分解成若干个规模较小的问题,递归求解这些问题,最后将问题的解合并成原问题的解。对于最大连续数组问题,分治算法的思路是将原数组分成左右两个部分,分别求出左部分、右部分和跨越中间点的最大连续数组,然后将这三个结果合并起来,得到原数组最大连续数组。 具体实现过程如下: 1.找到数组的中间位置mid,将数组分成左右两个部分A[0...mid]和A[mid+1...n-1]。 2.递归求解左部分和右部分的最大连续数组,得到左部分的最大连续数组leftMax、右部分的最大连续数组rightMax。 3.从mid位置开始,向左扫描数组,找到跨越中间点的最大连续数组leftCrossMax。 4.从mid+1位置开始,向右扫描数组,找到跨越中间点的最大连续数组rightCrossMax。 5.合并左部分、右部分和跨越中间点的最大连续数组,得到原数组最大连续数组。 下面是具体的代码实现: ```python def maxSubArray(A): if len(A) == 1: return A[0] mid = len(A) // 2 leftMax = maxSubArray(A[:mid]) rightMax = maxSubArray(A[mid:]) leftCrossMax = A[mid-1] leftSum = 0 for i in range(mid-1, -1, -1): leftSum += A[i] leftCrossMax = max(leftCrossMax, leftSum) rightCrossMax = A[mid] rightSum = 0 for i in range(mid+1, len(A)): rightSum += A[i] rightCrossMax = max(rightCrossMax, rightSum) return max(leftMax, rightMax, leftCrossMax+rightCrossMax) A = [2,-7,3,1,2,-3,5,-4,6,2] print(maxSubArray(A)) # 输出:11 ``` 时间复杂度为O(nlogn),空间复杂度为O(logn)。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值