洛谷P2249做题笔记 二分模板

洛谷P2249做题笔记 二分模板

这一篇我主要讲讲大佬的二分思想。
代码如下:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int n,num[1000006],m,k;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&num[i]);
	while(m--)
	{
		int l=1,r=n,ans=-1;
		scanf("%d",&k);
		while(l<=r)
		{
			int mid=(l+r)/2;
			if(num[mid]==k)
			{
				if(ans==-1)ans=mid;
				else ans=min(ans,mid);
			}
			if(num[mid]<k){l=mid+1;}
			else {r=mid-1;}
		}
		printf("%d ",ans);
	}
	return 0;
}

1.1
首先应该读题细致,题目给出案列:

11 3
1 3 3 3 5 7 9 11 13 15 15
1 3 6

不难发现,如果存在重复的应该输出最小的位置,这时候有意思的就来了,我对二分的理解是每次取半,但遇到符合项就输出,结束循环。这样做无法保证遇到重复的项时取最小位置。而大佬的题解时真的妙,下面我细品。
1.2

if(num[mid]==k)
{
	if(ans==-1)ans=mid;
	else ans=min(ans,mid);
}

这是这段代码的核心,如果要找出位置最小的,那么把思维简化点,这不就是要遍历全部数据一次吗?
所以大佬这样写的目的就是:把每次符合题意的点的位置记录下来,如果有多个位置满足题意,就取最小位置的那个点。而且在实现这个功能的前提下,大佬还满足了题目要求:当出现未出现的数时就输出‘-1’。奇妙的想法总是可以极大的化简步骤,这也是学习的方向。
再品味

if(num[mid]<k){l=mid+1;}
			else {r=mid-1;}

这段代码的核心目的就是保证能使结果位置最小。
你看,如果当s[mid]<k或者s[mid]>k的话,没话说,直接进行二分。
但如果s[mid]==k时,再向左进行二分,这就可以保证如果左边有位置小的相同数,就可以取到最小。
1.3
还有一个比较好的点就是其判断终止的条件
一开始我写的判断终止的条件是 r-l=1当时退一步越想越不对。发现我想的太窄了。
看大佬写代码,恍然大悟,原来可以这样操作,芜湖。


初解我是打算用递归函数,但是没有成功,等下继续尝试,成功会发文。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值