算法导论 第四章:分治法(一)

无论是在生活中还是在计算机科学中,“分而治之”的思想占据着举足轻重的地位,其原理如下:

    1)将一个复杂的问题分成若干个相同或相似的子问题

    2)递归求解子问题,当子问题规模很小时,可直接求解

    3)将所有子问题的解合并,即为原问题的解    


1.最大子数组问题(maximum-subarray problem)

 即一段非空的,连续的有最大和的一段子数组,如:

若采用暴力求解方法,时间复杂度是Θ(n²)。这里我们用分治法求解,将数组分为两个尽可能等长的子数组,那么最大子数组A[i...j]存在三种情况:

1)完全在子数组A[low...mid]中,满足low ≤ i ≤ j ≤ mid

2)完全在子数组A[mid+1...high]中,满足 mid<i≤j≤high

3)跨越中点(midpoint),满足low ≤ i ≤ mid < j ≤ high

当为情况3时,只需要寻找形如A[i...mid]和A[mid+1...high]的最大子数组,然后连接他们。伪代码如下:


其运行时间为:O(n)。

最大子数组算法的伪代码如下:

运行时间为:

最大子数组问题也可以在线性时间内求解,具体思想参加算法导论(第三版)课后题4.1-5.


三种求解方法的完整代码如下:

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

int maxSubarr_start;   //save the start index of maximum subarray with divid-and-conquer solution
int maxSubarr_end;

void Bruteforce_MaxSubarr(int a[],int n,int *res)
{//Brute-force solution
	int maxSum=INT_MIN;
	for(int i=0;i<n;i++)
		for(int j=i;j<n;j++)
	 		{ 
			int temp=0;
			for(int k=i;k<=j;k++)
				temp+=a[k];
			if(temp>maxSum)
				{ 
				maxSum=temp;
				res[0]=i;      //store the start index in array res[0]
				res[1]=j;      //store the end index in array res[1]
				res[2]=maxSum; //store the maxSum in array res[2]
				}
 			}
	}

int Crossing_MaxSubarr(int a[],int low,int mid,int high)
{//case:maximum subarray corssing mid index
	int left_sum=INT_MIN;
	int sum=0;
	for(int i=mid;i>=low;i--)
	{ 
		sum+=a[i];
		if(sum>left_sum)
	 	{
			left_sum=sum;
			maxSubarr_start=i;
			}
		}
	int right_sum=INT_MIN;
	sum=0;
	for(int j=mid+1;j<=high;j++)
	{
		sum+=a[j];
		if(sum>right_sum)
		{
			right_sum=sum;
			maxSubarr_end=j;
			}
		}
	return left_sum+right_sum;
	}
int DC_MaxSubarr(int a[],int low,int high)
{//divide-and-conquer solution
	if(high==low)        //only one element
		return a[low];

	//divid-and-conquer 
	int mid=(low+high)/2;
	int left_sum  = DC_MaxSubarr(a,low,mid);
	int right_sum = DC_MaxSubarr(a,mid+1,high);
	int cross_sum = Crossing_MaxSubarr(a,low,mid,high);

	if(left_sum>right_sum && left_sum>cross_sum)
		return left_sum;
	else if(right_sum>left_sum && right_sum>cross_sum)
		return right_sum;
	else
		return cross_sum;
	}
void LinearTime_MaxSubarr(int a[],int low,int high,int *res)
{//linear time solution 
	int temp=0;
	int maxSum=INT_MIN;
	int max_start,max_end;

	for(int i=low;i<=high;i++)
 	{
		temp+=a[i];
		if(temp>maxSum)       //if a[i]<=0 ,refuse
		{
			maxSum=temp;
	   		max_end=i;       //the end index of maximum subarray
		 	}  
		if(temp<0)			//start at a[i+1]
			temp=0;
			}	

	//find the start index of maximum subarray
	temp=maxSum;
	for(int j=max_end;j>=low;j--)
	{
		temp-=a[j];
		if(temp==0)
		{
			max_start=j;
			break;
			} 
		}
		
	//cout<<"the result:"<<max_start<<"   "<<max_end<<"   "<<maxSum<<endl;
	res[0]=max_start;
	res[1]=max_end;
	res[2]=maxSum;
	}

int main()
{
	int a[]={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
	int n=sizeof(a)/sizeof(int);

	/*-------the maximum-subarray with brute-force solution as following:------*/
	int *result0;
	result0=new int[3];
	Bruteforce_MaxSubarr(a,n,result0);
	cout<<"Brute-force solution as following:"<<endl;
	cout<<result0[0]<<"   "<<result0[1]<<"   "<<result0[2]<<endl;

	/*---the maximum-subarray with divid-and-conquer solution as following:----*/
	int result1;
	cout<<"Divid-Conquer solution as following:"<<endl;
	result1=DC_MaxSubarr(a,0,n-1);
	cout<<maxSubarr_start<<"   "<<maxSubarr_end<<"   "<<result1<<endl;
	
	/*-------the maximum-subarry with linear-time solution as following:------*/
	int *result2;
	result2=new int[3];
	cout<<"Linear-time solution as following :"<<endl;
	LinearTime_MaxSubarr(a,0,n-1,result2);
	cout<<result2[0]<<"   "<<result2[1]<<"   "<<result2[2]<<endl;

	return 0;
	}
运行结果:


第一个数表示最大子数组的起始位置;第二个是表示终止位置;第三个数表示最大子数组和。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值