7-4 二分查找

目录

题目描述

输入格式:

输出格式:

输入样例:

输出样例:

样例解释:

解题思路

举个例子:

详细代码(使用自带函数): 

详细代码(手写二分):

>>位运算


题目描述

请实现有重复数字的有序数组的二分查找。

输出在数组中第一个大于等于查找值的位置,如果数组中不存在这样的数,则输出数组长度加一。

输入格式:

输入第一行有两个数,第一个数为数组长度n(≤10^6),第二个数为需要查找的数。

接下来有n个整数,以空格或换行符分隔。

输出格式:

输出待查找的数的位置。

输入样例:

5 4
1 2 4 4 5

输出样例:

3

样例解释:

有5个数,查找4出现的位置,4第一次出现在第3个位置,所以输出3。

解题思路

二分需要使用在有单调性的数据中,单调递增或单调递减

使用二分求解需要定义查找规则,此题要查找某个数,所以规则是与要查找的数比大小。

举个例子:

根据题目输入样例

5 4
1 2 4 4 5

需要查找4,最先出现的位置
序列为

1 2 4 4 5存在sz数组中下标从1开始到n结束

第一次二分

左指针l=1

右指针r=n

中间值mid=(n+1)/2=3

对比发现

sz[mid]是4与4相等,由于最先出现的位置肯定靠左所以将右区间往左移动到mid,此时r=mid

第二次二分

mid=(l+r)/2=(1+3)/2=2

对比发现

sz[mid]是2比4小,可以得出要找的值在2的右边,所以左区间往右移动此时l=mid+1

此时l==r都指向3所以3所在下标的元素sz[3]即为第一个要查找的m的值4下标即为3

详细代码(使用自带函数): 

lower_bound查找数组中第一个小于等于某个数的元素的地址

减去数组的开始地址后即要查找元素的下标

#include<iostream>
using namespace std;
const int N=1e6+7;
int sz[N];
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>sz[i];
	}
	cout<<lower_bound(sz+1,sz+1+n,m)-sz;
}

详细代码(手写二分):

#include<iostream>
using namespace std;
const int N=1e6+7;
int sz[N];
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>sz[i];//存储数组下标从1开始
	}
	int l=1,r=n;//左端点最小为1,右端点最大为n,因为下标为1到n
	while(l<r)//如果l>=r则说明已经找到答案了
	{
		int mid=(l+r)/2;//查找中间值,假设为可能值,可以用mid=(l+r)>>1;
		if(sz[mid]<m)//如果查找到的值小于需要查找的值,说明答案靠右,因为要查找的值需要变大一些,左区间往右靠。
		{
			l=mid+1;
		}
		else//如果查找到的值大于需要查找的值,说明答案靠左,因为要查找的值需要变小一些,右区间往左靠。
		{
			r=mid;
		}
	}
	if(sz[l]>=m)//找到了输出这个数的下标。
    {
	    cout<<l;
    }
	else//如果没找到输出n长度+1
    {
	    cout<<n+1;
    }
}

>>位运算

感兴趣的可以看 

>>是位运算与<<的方向相反

举个例子

2>>1的意思是2/2=1

即把2看作二进制10

将整体往右移动一位

即10移动变为1

1的十进制为1

2<<1的意思是2*2=4

即把2看作二进制10

将整体往左移动一位

即10移动变为100

100的十进制为4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星与星熙.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值