算法导论之分治策略:最大子数组问题

我们先说一下分治策略的基本步骤:首先我们要递归的求解一个问题,在每层的递归中会分为一下三个过程:

分解:将大问题划分为子问题,子问题形同大问题,只是规模更小。

解决:递归的求解出子问题。

合并:将子问题的答案合并为原问题的解。

我们首先介绍实现的算法:

我们要找数组A的最大子数组,那么我们需要把数组A分为规模尽可能相等的两个子数组:数组A[low..mid]和数组A[mid+1..high]。

接着我们需要找出数组A[low..mid]和数组A[mid+1..high]中的最大子数组,然后与跨过中点mid(low=<i=<mid<j=<high)的最大子数组的值进行比较。

如果用这个方法那么时间复杂度为:

θ(1) 若n = 1

T(n)  =

2T(n/2) + θ(n)若n>1

我们可以用主方法(master)求递归式的解,也可以用数学归纳法求出。

所以该算法的时间复杂度为:T(n)=θ(nlgn)。

而如果用暴力破解的方法,时间复杂度为:θ(n^2)。

用Java代码实现如下:

package algorithms;

import java.util.ArrayList;

public class FINDMAXIMUMSUBARRAY {
	ArrayList<Integer> A;
	int High = 0;
	int Low = 0;
	int Max_Left = 0;
	int Max_Right = 0;
	int sum = 0;

	public FINDMAXIMUMSUBARRAY(ArrayList<Integer> arrayList, int hight, int low) {
		A = arrayList;
		this.Low = low;
		this.High = hight;
	}
	private FINDMAXIMUMSUBARRAY doFind(){
		if (this.Low == this.High) {
			this.sum = this.A.get(Low-1);
			this.Max_Left = this.Low;
			this.Max_Right = this.High;
			return this;
		}
		else{
			int mid = (this.High + this.Low)/2;
			FINDMAXIMUMSUBARRAY FMSL = (new FINDMAXIMUMSUBARRAY(this.A, this.High, mid+1)).doFind();
			FINDMAXIMUMSUBARRAY FMSR = (new FINDMAXIMUMSUBARRAY(this.A, mid, this.Low)).doFind();
			FINDMAXIMUMSUBARRAY FMSM = this.doFindCross();
			if (FMSL.sum > FMSR.sum && FMSL.sum > FMSM.sum) {
				return FMSL;
			}else if (FMSR.sum > FMSL.sum && FMSR.sum > FMSM.sum) {
				return FMSR;
			}else {
				return FMSM;
			}
		}
	}

	private FINDMAXIMUMSUBARRAY doFindCross() {
		FINDMAXIMUMSUBARRAY FC = new FINDMAXIMUMSUBARRAY(A, this.High, this.Low);
		int mid = (this.High + this.Low)/2;
		int left_sum= Integer.MIN_VALUE;
		int sum = 0;
		for (int i = mid; i >= this.Low; i--) {
			sum += A.get(i-1);
			if (sum > left_sum) {
				left_sum = sum;
				FC.Max_Left = i;
			}
		}
		int right_sum = Integer.MIN_VALUE;
		sum = 0;
		for (int i = mid+1; i <= this.High; i++) {
			sum += A.get(i-1);
			if (sum > right_sum) {
				right_sum = sum;
				FC.Max_Right = i;
			}
		}
		FC.sum = left_sum  + right_sum;
		
		return FC;
	}
	public static void main(String[] args) {
		ArrayList<Integer> arrayList = new ArrayList<Integer>();
		arrayList.add(13);
		arrayList.add(-3);
		arrayList.add(-25);
		arrayList.add(20);
		arrayList.add(-3);
		arrayList.add(-16);
		arrayList.add(-23);
		arrayList.add(18);
		arrayList.add(20);
		arrayList.add(-7);
		arrayList.add(12);
		arrayList.add(-5);
		arrayList.add(-22);
		arrayList.add(15);
		arrayList.add(-4);
		arrayList.add(7);
		FINDMAXIMUMSUBARRAY f= new FINDMAXIMUMSUBARRAY(arrayList, arrayList.size(), 1).doFind();
		for (int i = f.Max_Left; i <= f.Max_Right; i++) {
			System.out.print(arrayList.get(i-1) + " ");
			
		}
		System.out.println();
		System.out.println("this is the sum :" + f.sum);

	}

}
求这类问题时候,分治策略不一定都是最好的选择,当我们求斐波那契数列(Fibonacci sequence)的时候,如果给的n过大(比如50),那么程序的执行时间就会很长。

所以用什么方法视情况而定。

参考资料:
算法导论

备注:
转载请注明出处:http://blog.csdn.net/wsyw126/article/details/50810702
作者:WSYW126

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值