整数二分两个模板
1.确定左半边的边界
while(nLeft < nRight)
{
//注意此处 多加了一个1
//如若不加1 当Left 和 Right的值只相差1的时候 那么Mid 的值就为 Left
//此时若刚好满足条件 则执行Left = Mid 就造成死循环
int nMid = (nRight + nLeft + 1)/2;
if(Check(nMid))
{
//即当前找到的Mid满足要求了 需要查看Mid的右边是否也满足要求
nLeft = nMid;
}
else
{
//当前找到的Mid不满足要求 需要查看Mid的左边是否满足要求
nRight = nMid - 1;
}
}
将区间分为了[left mid-1]和[mid right]
2.确定右半边的边界
while(nLeft < nRight)
{
//此处不会造成死循环
int nMid = (nRight - nLeft)/2 + nLeft;
if(Check(nMid))
{
//即nMid和nMid右边的都满足要求了 需要查看左边的是否满足
nRight = nMid;
}
else
{
//nMid 不满足要求
nLeft = nMid + 1;
}
}
将区间分为了[left mid]和[mid+1 right]
3.一个例题数的范围
给定一个按照升序排列的长度为n的整数数组,以及 q 个查询。
对于每个查询,返回一个元素k的起始位置和终止位置(位置从0开始计数)。
如果数组中不存在该元素,则返回“-1 -1”。
输入格式
第一行包含整数n和q,表示数组长度和询问个数。
第二行包含n个整数(均在1~10000范围内),表示完整数组。
接下来q行,每行包含一个整数k,表示一个询问元素。
输出格式
共q行,每行包含两个整数,表示所求元素的起始位置和终止位置。
如果数组中不存在该元素,则返回“-1 -1”。
#include <bits/stdc++.h>
using namespace std;
#define MAX 100010
int nArr[MAX];
int nLen;
int nTime;
int nQuery;
int main(int argc, char** argv)
{
scanf("%d%d",&nLen, &nTime);
for(int i = 0; i < nLen; i++)
{
scanf("%d",&nArr[i]);
}
while(nTime--)
{
scanf("%d",&nQuery);
int nLeft = 0;
int nRight = nLen - 1;
//求取右半边的边界
while(nLeft < nRight)
{
int nMid = (nLeft + nRight)/2;
//nMid右边的数都>=nQuery 需要去左边寻找 nMid也可能是边界
if(nArr[nMid] >= nQuery)
{
nRight = nMid;
}
else
{
nLeft = nMid + 1;
}
}
if(nQuery != nArr[nLeft])
{
cout<<"-1 -1"<<endl;
}
else
{
cout<<nLeft<<" ";
int nLeft = 0;
int nRight = nLen - 1;
//求取左半边的边界
while(nLeft < nRight)
{
int nMid = (nLeft + nRight + 1)/2;
//nMid左边的数都<=nQuery 需要去右边寻找 nMid也可能是边界
if(nArr[nMid] <= nQuery)
{
nLeft = nMid;
}
else
{
nRight = nMid - 1;
}
}
cout<<nLeft<<endl;
}
}
return 0;
}