C/C++ 二分、倍增

设array[]为一单调递增序列。

# include <bits/stdc++.h>
using namespace std;


TYPE array[SIZE];  // 单调递增序列(下标1~length)
int length;  // 数组中的元素个数

二分

二分的基础用法是在单调序列或函数中进行查找。
平均时间复杂度:O(logn)(数据规模为n)。

整数集合上的二分:

保证最终答案处于闭区间[l, r]以内,循环以l=r结束。

在序列array[]中查找 >=x 的数中最小的一个:

int Successor(int a[], int x, int l, int r) {
	while (l < r) {
		int mid = (l+r)>>1;
		if (a[mid] >= x) r = mid; else l = mid+1;
	}
	return a[l];
}

// main
int ans1 = Successor(array, x, 1, length);

在序列array[]中查找 <=x 的数中最大的一个:

int Predecessor(int a[], int x, int l, int r) {
	while (l < r) {
		int mid = (l+r+1)>>1;
		if (a[mid] <= x) l = mid; else r = mid-1;
	}
	return a[l];
}

// main
int ans2 = Predecessor(array, x, 1, length);
  • 不同需求的二分需要根据边界进行不同调整,防止死循环。
  • 处理无解情况:把最初的二分区间[1, n]分别扩大为[1, n+1]和[0, n],如果最后二分终止于扩大后的越界下标上,则说明序列中不存在所求的数。
实数域上的二分:

确定所需的精度eps,以 r - l > eps 为循环进行条件。
需要保留k为小数时,可令 r - l >= 10-(k+1)

double Dichotomy(double l, double r) {
	while (r - l > eps) {
		double mid = (l+r)/2;
		if (calc(mid)) r = mid; else l = mid;  // calc()根据需要自定义
	}
	return l;
}

// main
int ans = Dichotomy(左边界, 右边界);

精度不易确定时,也可采用循环固定次数的二分方法。

倍增

同样需要单调条件。
当状态空间过大,线性递推无法满足需求时,可以通过“成倍增长”的方式进行递推。(相比二分来讲,当目标位置较靠前时倍增算法更优)
平均时间复杂度:O(logn)

在序列array[]中查找 <=x 的数中最大的一个:

int Doubling(int a[], int x, int s, int e) {  // 在闭区间[s, e]中求解
	int p = s, d = 1;
	while (d) {
		if (a[p+d] <= x) p += d, d = min(e-p, d<<1);
		else e = p+d - 1, d >>= 1; 
	}
	return a[p];
}

// main
int ans = Doubling(array, x, 1, length);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值