二分法,最大子数组问题(分治法)

二分法简单,从排好序的数组里找数。

时间复杂度就是O(logn)

//二分法查找
#include <iostream>
#define N 100

using namespace std;
inline void Swap(int &a,int &b);
void FastSort(int a[],int left, int right);
bool Find(int a[],int n,int num,int index[],int &count);//n数组个数,num要查找的数,index,返回索引数组,值是0到n-1,count是index的大小 
int main()
{
	int a[N]={1,2,3,3,5,6,7,8,3,3,3,3,39,10};
	
	int index[N]={0},count=0;
	int num;
	cin>>num;
	FastSort(a,0,N-1);
	cout<<Find(a,N,num,index,count)<<endl;
	cout<<"count="<<count<<endl;
} 

bool Find(int a[],int n,int num,int index[],int &count)
{
	int i;
	count = 0; 
	int middle = (n-1)/2;//因为n是数组个数,所以这里的索引都是n-1进行处理 
	int index_left = 0;
	int index_right = n-1;
	while(index_left!=index_right) 
	{	
		if(a[middle]<num)
		{
			index_left = middle;
			middle = (index_left+index_right)/2;
		} 
		else if(a[middle]>num)
		{
			index_right = middle;
			middle = (index_left+index_right)/2;
		}
		else
		{
			index[count] = middle;
			count++;
			int middle_tmp = middle-1;
			while(a[middle_tmp]==num)
			{
				index[count] = middle_tmp;
				count++;
				middle_tmp--;
			}
			middle_tmp = middle+1;
			while(a[middle_tmp]==num)
			{
				index[count] = middle_tmp;
				count++;
				middle_tmp++;
			}
			break;
		}
	}

	if(count==0) return false;
	else return true;
}




inline void Swap(int &a,int &b)
{
	int temp;
	temp = a;
	a = b;
	b = temp;
}
void FastSort(int a[],int left, int right)//aê?êy×é£?left,rightê?êy×éμ??÷òy£??′0oín-1 
{
	if(left >= right)
		return;
	int reference = a[right];//°?óò±?μ?×?2???μ??°£?×?oóDè×ó±?ê?′óóú2???£?óò±?ê?D?óú2??? 
	int index_left = left,index_right = right;
	int i = 0;
	while(index_left!= index_right)
	{
		while(index_left!=index_right)//á????÷òy??μ?ò??eμ??°
		{
			if(a[index_left]>reference) break;//?ò?òμ?á?ó|??íùóò·?μ?êy
			index_left++;//???òμ??í?ìD?íùóò???÷ 
		}
		//cout<<"left="<<index_left<<endl;
		while(index_left!=index_right)
		{
			if(a[index_right]<reference) break;
			index_right--;
		} 
	//	cout<<"right="<<index_right<<endl;
		//?òμ?á?????????2???μ?êy
		Swap(a[index_left],a[index_right]); 

	}
	//×?oó×óóò??????μ?ò??eμ?ê±oò£?òò?a?èò??ˉμ?×ó±?????£??ùò?×?oóê?×ó±???????μ?á? óò±?′óóú2???μ?êy×é?ùò?°?2????ú×?oó?a????μ?μ?êy??ò???
	Swap(a[index_left],a[right]); 

	FastSort(a,left,index_left-1);
	FastSort(a,index_left+1,right);
	
}

这个二分法总感觉很啰嗦,参数太多,因为感觉最重要知道存在否即可。

刚看别人的方法感觉很全面,找到这个数的上下界的索引,就完美了

//二分法,返回数的上下界
int FindIndexUp(int a[],int left,int right,int num);//num要查找的数 ,返回上界的索引(最后一个num) 
int FindIndexDown(int a[],int left,int right,int num);//num要查找的数 ,返回下界的索引(第一个num)
pair<int,int> FindIndexDownToUp(int a[],int left,int right,int num);

int FindIndexUp(int a[],int left,int right,int num){
	int middle=(right-left)/2,index_left=left,index_right=right;
	while(index_left<index_right){
		middle=(index_right-index_left)/2;
		if(a[middle]>num){
			index_right = middle;
		}
		else if(a[middle]<num){
			index_left = middle;
		}
		else{
			int index_tmp=middle;
			while(a[index_tmp]==num) index_tmp++;
			if(index_tmp>right) return right;
			else	return index_tmp-1;
		}
	}
	return -1;
} 

int FindIndexDown(int a[],int left,int right,int num){
	int middle=(right-left)/2,index_left=left,index_right=right;
	while(index_left<index_right){
		middle=(index_right-index_left)/2;
		if(a[middle]>num){
			index_right = middle;
		}
		else if(a[middle]<num){
			index_left = middle;
		}
		else{
			int index_tmp=middle;
			while(a[index_tmp]==num) index_tmp--;
			if(index_tmp<left) return left;
			else	return index_tmp+1;
		}
	}
	return -1;
} 

pair<int,int> FindIndexDownToUp(int a[],int left,int right,int num){
	int index_up=FindIndexUp(a,left,right,num);
	int index_down=FindIndexUp(a,left,right,num);
	return make_pair(index_down,index_up);
}

回头看一眼别人的,发现别人这个很简洁啊,可以记下来学习一下这种简洁的做法。,,这个返回的是target上面的数,并且1,2,3,3,3,3,3的情况,认为不存在上界,返回-1。


int BSearchUpperBound(int array[], int low, int high, int target)
{
    //Array is empty or target is larger than any every element in array 
    if(low > high || target >= array[high]) return -1;
    
    int mid = (low + high) / 2;
    while (high > low)
    {
        if (array[mid] > target)
            high = mid;
        else
            low = mid + 1;
        
        mid = (low + high) / 2;
    }

    return mid;
}
int BSearchLowerBound(int array[], int low, int high, int target)
{
    //Array is empty or target is less than any every element in array
    if(high < low  || target <= array[low]) return -1;
    
    int mid = (low + high + 1) / 2; //make mid lean to large side
    while (low < high)
    {
        if (array[mid] < target)
            low = mid;
        else
            high = mid - 1;
        
        mid = (low + high + 1) / 2;
    }

    return mid;
}
pair<int, int> SearchRange(int A[], int n, int target) 
{
    pair<int, int> r(-1, -1);
    if (n <= 0) return r;
    
    int lower = BSearchLowerBound(A, 0, n-1, target);
    lower = lower + 1; //move to next element
    
    if(A[lower] == target)
        r.first = lower;
    else //target is not in the array
        return r;
    
    int upper = BSearchUpperBound(A, 0, n-1, target);
    upper = upper < 0? (n-1):(upper - 1); //move to previous element
    
    //since in previous search we had check whether the target is
    //in the array or not, we do not need to check it here again
    r.second = upper;
    
    return r;
}

最大子数组的问题:

,在一个数组里面找和最大的子数组。

分解开来,从middle开始,最大子数组存在midd左边,右边,这两种情况可以递归分解问题,第三种情况是最大子数组会跨过middle,这样的话,最大子数组就是i到middle到j的数组,这样对左右i到middl和j到middle的情况可以遍历找一下这样解决。

//最大子数组问题
#include <iostream>
#define N 16
using namespace std;
typedef pair<pair<int,int>,int> sub; //定义一个存子数组的数据类型,前一个pair是子数组的左右索引,后一个是子数组的和 

sub FindMaxSub(int a[],int left,int right);//left,right是左右索引 
sub FindMaxCrossSub(int a[],int left,int middle,int right);//这种事最大子数组跨过middle的情况
int main()
{
	//sub a;
	//a = make_pair(make_pair(0,3),6); 
	//cout<<a.first.first<<endl;
	//int a[4]={13,-3,20,-3};
	int n=N;
	int a[N]={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-55,-22,15,-4,7};
	sub max_sub = FindMaxSub(a,0,n-1);
	cout<<"left="<<max_sub.first.first<<endl;
	cout<<"right="<<max_sub.first.second<<endl;
	cout<<"sum="<<max_sub.second<<endl;
	return 0;
}

sub FindMaxSub(int a[],int left,int right)//这里a用数组头指针,left,right就不是从0开始的索引了 
{
	if(left==right) return make_pair(make_pair(left,right),a[left]);
	int i;
	int middle = (left+right)/2;
	sub left_sub = FindMaxSub(a,left,middle);
	cout<<"left sum="<<left_sub.second<<endl;
	sub right_sub = FindMaxSub(a,middle+1,right);
	cout<<"right sum="<<right_sub.second<<endl;
	sub cross_sub = FindMaxCrossSub(a,left,middle,right);
	cout<<"cross sum="<<cross_sub.second<<endl;
	if(left_sub.second>right_sub.second && left_sub.second>cross_sub.second) return left_sub;
	else if(right_sub.second>left_sub.second && right_sub.second>cross_sub.second) return right_sub;
	else return cross_sub;
	
}


sub FindMaxCrossSub(int a[],int left,int middle,int right)
{
	int sum_tmp=0;
	int sum_left=0,sum_right=0;
	int index_left = middle;
	int index_right = middle+1;
	int i;
	for(i=middle;i>=left;i--)
	{
		sum_tmp += a[i];
		if(sum_left<sum_tmp)
		{
			index_left = i;
			sum_left = sum_tmp;
		}
	}
	sum_tmp = 0;
	for(i=middle+1;i<=right;i++)
	{
		sum_tmp +=a[i];
		if(sum_right<sum_tmp)
		{
			index_right = i;
			sum_right = sum_tmp;
		}
	}
	return make_pair(make_pair(index_left,index_right),sum_left+sum_right);
	
}

猜你喜欢

转载自blog.csdn.net/zhangzhi2ma/article/details/82559975