「算法导论」:分治法求最大子数组

时间复杂度:o(nlgn)

分治法求最大子数组关键的问题在于如果去划分递归,当把原数组分解为规模相近的两个子数组的时候,当前数组的最大子数组只会在三种情况之一出现,要么最大子数组出现在左边子数组,要么最大子数组出现在右边子数组,要么就出现在横跨两子数组相交结点的连续子数组,前两种情况是比待求问题更小的子问题,可直接用递归求得,最后一种情况中要使得子数组最大,那必然是左侧取最大,右侧取最大的合并。这样,只需分别遍历交点左右两侧求得最大子数组即可。在三种情况下求得的最大子数组再取一个最大的就是当前数组的最大子数组了。

代码:

/*************************************************************************
	> File Name: max_sub_array.cpp
	> Author sangoly
	> Mail: sangoly@aliyun.com 
	> Created Time: 2014年07月07日 星期一 15时50分15秒
 ************************************************************************/

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

class Range {
public:
	int start;
	int end;
	int sum;

	Range(int mStart, int mEnd, int mSum) : start(mStart), end(mEnd), sum(mSum) {}
 
	bool operator>(Range& other) const {
		return this->sum > other.sum;
	}
};

Range* find_max_crossing_subarray(int list[], int start, int middle, 
		                                  int end) {
	int left_sum = numeric_limits<int>::min();
	int sum = 0;
	int l_start;
	for (int i = middle; i >= start; i--) {
		sum += list[i];
		if (sum > left_sum) {
			left_sum = sum;
			l_start = i;	
		}
	}

	int right_sum = numeric_limits<int>::min();
	sum = 0;
	int r_end;
	for (int i = middle + 1; i <= end; i++) {
		sum += list[i];
		if (sum > right_sum) {
			right_sum = sum;
			r_end = i;
		}
	}

	return new Range(l_start, r_end, left_sum + right_sum);
}

Range* max_sub_array(int list[], int start, int end) {
	if (start == end) 
		return new Range(start, end, list[start]);	
	int middle = (start + end) / 2;
	Range* max_range_left = max_sub_array(list, start, middle);
	Range* max_range_right = max_sub_array(list, middle + 1, end);
	Range* max_range_crossing_middle = find_max_crossing_subarray(list, start, middle, end);
	if ((*max_range_left > *max_range_right) 
			&& (*max_range_left > *max_range_crossing_middle)) { 
		delete max_range_right;
		delete max_range_crossing_middle;
		return max_range_left;
	}
	else if ((*max_range_right > *max_range_left) 
			&& (*max_range_right > *max_range_crossing_middle)) { 
		delete max_range_left;
		delete max_range_crossing_middle;
		return max_range_right;
	}
	else {
		delete max_range_left;
		delete max_range_right;
		return max_range_crossing_middle;
	}
}

int main() {
	int list[] = {13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5,
					-22, 15, -4, 7};
	Range* max_range = max_sub_array(list, 0, sizeof(list) / sizeof(int) - 1);
	cout<<"The max sub array's index from "<<max_range->start<<" to "
		<<max_range->end<<endl;
	cout<<"The max sub array value is "<<max_range->sum<<endl;
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值