二分算法题例——肥成的朋友

题目描述

一群喵,每只喵都有一个数字,现在肥成想知道它的朋友有几个,肥成会告诉我们它的朋友的数字的范围。

输入格式

第一行两个整数N,T,代表共有N只喵,T次询问。
第二行是N个整数,代表N只喵的数字。
之后T行,每行两个整数l,r,代表是肥成的朋友的数字的范围。

数据范围

对于50%50%的数据有1≤n≤1000,1≤a​i​​≤1000,T=1000。
对于80%80%的数据有1≤n≤10000,1≤a​i​​≤10000,T=1000。
对于100%100%的数据有1≤n≤100000,1≤a​i​​≤100000,T=1000。

输出格式

对于每个询问,请输出肥成的朋友的个数。

样例解释

样例输入

10 3
1 3 4 4 5 8 8 10 10 10
2 6
4 8
6 7

样例输出

4
5
0

题目做法较多,但推荐使用二分,效率很高;

枚举也是可行方案,但在数据规模庞大时效率低下。

#include <iostream>
#include <algorithm>

static unsigned int binary_search1(register unsigned int * range, register unsigned int head, register unsigned int rear, register unsigned int target) {
	register unsigned int middle = (head + rear) / 2;
	if (range[middle] < target) {
		if (middle == rear) {
			return 0;//无效
		}
		if (range[middle + 1] >= target) {
			return middle + 1;
		}
		if ((middle + rear) / 2 == middle) {
			return binary_search1(range, middle, rear + 1, target);
		}
		return binary_search1(range, middle, rear, target);
	}
	if (range[middle] > target) {
		if (middle == 0) {
			return 0;//有效
		}
		if (range[middle - 1] < target) {
			return middle;
		}
		if ((head + middle) / 2 == middle) {
			return binary_search1(range, head, middle + 1, target);
		}
		return binary_search1(range, head, middle, target);
	}
	else {
		while (range[middle] == target) {
			if (middle == 0) {
				return middle;
			}
			middle--;
		}
		return middle + 1;
	}
}//寻找大于等于目标的最左边的数

static unsigned int binary_search2(register unsigned int* range, register unsigned int head, register unsigned int rear, register unsigned int target) {
	register unsigned int middle = (head + rear) / 2;
	if (range[middle] > target) {
		if (middle == 0) {
			return 0; //无效
		}
		if (range[middle - 1] <= target) {
			return middle - 1;
		}
		if ((head + middle) / 2 == middle) {
			return binary_search2(range, head, middle + 1, target);
		}
		return binary_search2(range, head, middle, target);
	}
	if (range[middle] < target) {
		if (middle == rear) {
			return middle;
		}
		if (range[middle + 1] > target) {
			return middle;
		}
		if ((middle + rear) / 2 == middle) {
			return binary_search2(range, middle, rear + 1, target);
		}
		return binary_search2(range, middle, rear, target);
	}
	else {
		while (range[middle] == target) {
			if (middle == rear) {
				return middle;
			}
			middle++;
		}
		return middle - 1;
	}
}//寻找小于等于目标的最右边的数

int main() {
	register unsigned int n, t, * a, l, r;
	std::cin >> n >> t;
	a = new unsigned int[n];
	for (register unsigned int i = 0; i < n; i++) {
		std::cin >> a[i];
	}
	std::sort(a, a + n);
	for (register unsigned short i = 0; i < t; i++) {
		std::cin >> l >> r;
		std::cout << binary_search2(a, 0, n - 1, r) - binary_search1(a, 0, n - 1, l) + 1 << "\n";
	}
	return 0;
}

两者(穷举 vs 二分)对比结果如下:

提示:需注意使用二分时应注意避免中间值反复取相同的值导致死循环从而堆栈溢出,应该注意判断新计算的中间下标是否与现有的重复

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值