二分算法

二分查找

二分查找需要找到序列中存在的元素的下标,如果值不存在就返回-1,因此循环的条件需要设置为left<=right,当left>right说明所查找的元素不存在,循环中止。

int binarySearch(int a[],int left,int right,int target) {
	//当左端点小于等于右端点时进行循环
	while(left<=right) {
		//防止超过int范围
		int mid = left+(right-left)/2;
		//当中点的值为搜索目标,返回中点下标
		if(a[mid]==target) return mid;
		//当中点的值小于目标,说明目标在中点右边
		else if(a[mid]<target) left=mid+1;
		//当中点的值大于目标,说明目标在中点左边
		else right=mid-1;
	}
	//当左端点大于右端点说明没有找到
	return -1;
}

搜索必须要找到点或者点不存在时返回-1,所以右端点是n-1而不是n(数组的大小为n因此取不到)

//设n为数组a的大小
//设x为要查找的元素
binarySearch(a,0,n-1,x);

序列中第一个大于等于x元素的位置

如果序列中没有要找的x,也可以理解为如果存在x,那么x的位置应该是哪里。比如要找出往这个序列中插入x的位置,就可以用如下的方法。

int lower_bound(int a[],int left,int right,int x) {
	//找出第一个(可能有多个相同的点)大于等于x的元素的位置
	while(left<right) {
		int mid = left+(right-left)/2;
		//当中点的值大于等于x,说明目标在中点处或者中点的左边
		if(a[mid]>=x) right = mid;
		//当中点的值小于x,说明目标在中点的右边
		else left = mid + 1;
	}
	//当left==right时说明只有一个点,返回left和right都可以
	return left;
}

查找位置时不一定存在符合条件的元素,所以右端点可能在最大的元素后面,所以取得到n(数组的大小为n,即可以插到数组的后一个位置上)

//设n为数组a的大小
//设x为要查找的元素
lower_bound(a,0,n,x);

序列中第一个大于x元素的位置

这个的做法和上述的类似,只需要改变等号的位置即可。

int upper_bound(int a[],int left,int right,int x) {
	//找出第一个大于x的元素的位置
	while(left<right) {
		int mid = left+(right-left)/2;
		//当中点的值大于x,说明目标在中点处或者中点的左边
		if(a[mid]>x) right=mid;
		//当中点的值小于等于x,说明目标在中点的右边
		else left = mid + 1;
	}
	return left;
}

同理,此处也不一定存在符合条件的元素,所以右端点可能在最大的元素后面,所以取得到n。

//设n为数组a的大小
//设x为要查找的元素
upper_bound(a,0,n,x);

木棒切割问题

木棒切割问题是二分问题的一个变种:给出N根木棒,长度均已知,希望能够通过切割它们来得到至少K段等长的木棒,问这些木棒最长能够切成多长?

int slice(int a[],int left,int right,int k) {
	while(left<right) {
		int mid = left + (right-left)/2;
		//计算按当前的中间长度切割可以得到多少根木棒
		int cnt=0;
		for(int i=0; i<3; i++) {
			cnt+=a[i]/mid;
		}
		//如果cnt大于k,说明切的太短,可以增长每段的长度
		if(cnt>k) {
			left=mid+1;
		}
		//如果cnt小于等于k,说明切的太长或者正好合适
		else {
			right=mid;
		}
	}
	return left;
}

这里可以确定最长的长度不会超过最长那段木棒的长度,最短的长度一定大于0

//输入有序数组并且记录下最长的木棒长度为max_len
//设k为所需要得到的木棒数量
slice(a,0,max_len,k);

编程实现的一个重要细节

当使用int类型的数据时,由于C++的语言特性,mid求出来会自动向下取整,这就会引发一个问题!
举一个例子,当left为5,right为6时,mid会得到5,此时在遇到某些特殊的情况后,假设条件执行了改变left的那组代码,那么当代码写为

if(条件)
left=mid;
else
right=mid-1;

这样的形式后,就会导致left被赋值为mid,但是mid已经和left相等,导致循环while(left<right)永远成立。
所以当使用会向下取整的编程语言进行int型代码的编写时,必须写成如下的形式。(注意=的情况总是和+1的代码在相反的代码段里)

if(条件)
left=mid+1;
else
right=mid;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值