二分:精确二分;分割木棒;快速幂;随机数排序算法

二分查找:

归并排序:

  • 非递归实现

二分

基于有序序列的查找算法

1.严格递增序列
int BinarySearch(int a[], int low, int high, int x)
{
	int mid;
	while (low <= high)//要有等于号,可能恰好就在中间,不等于的话就搜不到了。
	{
		mid = (low + high) / 2;
		if (**x == a[mid]**) return mid;
		if (x < a[mid]) {
			high = mid - 1;
		}else {
			low = mid + 1;
		}
	}
	return -1;
}

x == a[mid]: 条件是等于x的元素位置

2.非严格递增

返回第一个大于等于x的位置(可能有重复x) || 返回第一个大于x的位置

int BinarySoloSearch(int a[], int low, int high, int x)
{
	//返回第一个大于等于x的地方(可能有重复x)
	//寻找第一个满足某条件的元素位置
	//因为mid 就是我要寻找的位置
	int mid;
	while (low < high) { //退出条件 low == high 唯一位置
		mid = (low + high) / 2;
		if ( **a[mid] >=x** ) { //寻找第一个>=x 的数 :现在中间的数比x要大
			high = mid; // 我要去左区间找
		}
		else {
			low = mid + 1;
		}
	}
	return low;
}

a[mid] >=x的不同:满足某一条件的元素位置:往哪个区间找。

3.二分法拓展:精度问题
#include<iostream>
#include<cmath>
using namespace std;
const double esp = 1e-5; //(10^5)

double eal() {
	double left = 1, right = 2, mid;
	while (right - left > esp) {//退出条件:精度小于10^-5
		mid = (left + right) / 2;
		if (pow(mid, 2) > 2) {//平方比二大 比 判断 该数比根号2大精确
			right = mid;
		}
		else {
			left = mid;
		}
	}
	return mid;
}

int main()
{
	cout << eal();
}
1.41421

可以转换为求方程的解
木棒切割: 有两端,切割的长度越长,木棒椴数越少。

木棒切割

切割成K段:求长度相等的木棒 : 最长能有多长

int cut(int a[], int size, int length)
{
	int sum = 0;
	for (int i = 0; i <size; i++)
	{
		sum += a[i] / length;
	}
	return sum;
}

int main()
{
	int sticks[100],n,K;
	cin >> n>>K;
	for (int i = 0; i < n; i++)
	{
		cin >> sticks[i];
	}
	sort(sticks, sticks + n);
	int k,low = 0, high = sticks[n-1],mid;
 // 最大取最大的那根木棒
	while (low <= high) { // 当low>high的时候跳出
		mid = (high+low)/2;
		k = cut(sticks, n,mid);
		if (k < K && cut(sticks, n, mid - 1) == K) break;//找到第一个切出来的数目比需要切出来的数目小的(找长度最大的)跳出
		if (k < K && cut(sticks, n, mid - 1) != K) high = mid;
		else low=mid+1;
	}
	if (low > high)cout << mid;
	else cout << mid-1;  //长度变小一点就满足”最长“
}

快速幂

longlong 可以存19位数;iint可以存10位数9(十进制)

将幂降下来:利用分治分解:

方法一:递归
  • 递归边界 a0=1
  • 递归式:b%2 ==0: ab = ab/2 * ab/2
    奇数 ab=a * ab-1(换成偶数)
#include<iostream>
typedef long long LL;
using namespace std;
LL binaryPow(LL a, LL b, LL c)
{
	if (b == 0) return 1;
	if (b % 2)return a * binaryPow(a, b - 1, c)%c;
	else{
	LL temp = (binaryPow(a, b / 2, c);//只调用一次
	 return  temp*temp %c;
	 }
}
int main()
{
	LL a, b, c;
	cin >> a >> b >> c;
	cout << binaryPow(a, b, c);
}

b%2b&1等价。b与1与操作。b的末尾为1则为奇数返回1

细节:

1.如果a>m:则先a%m
2.m==1:结果为0

方法二:迭代

利用二进制来算 a13=a1011=a8 * a4 * a1

LL binaryPow(LL a, LL b, LL c)
{
	LL sum = 1;
	while (b > 0) { // 如果b还存在的话
		if (b & 1) {//二进制如果末尾为1则需要计算
			sum = sum * a % c;
		}
		a = a * a % c; //往左进制+1
		b = b>> 1;//b右移; b>>=1;
	}
	return sum;
}
int main()
{
	LL a, b, c;
	cin >> a >> b >> c;
	cout << binaryPow(a, b, c);
}

随机数

#include<time.h>
main(){
srand((unsigned)time(NULL));

rand()%(n)+1;
(1~(n))
大范围(的随机数)
[0-1的浮点数]
round(1.0*rand()/RAND_MAX*[随机数长度]+起始位置)
比如[low,high]内的随机数index
int index = rand(1.0*rand()/RAND_MAX*(high-low)+low)  
[0+low ~ high-low+low]

随机排序算法

从无序数组中到找第K大的数

#include<iostream>
#include<ctime>
using namespace std;

int RandPartition(int a[], int low, int high)
{
	int index = (int)round(1.0 * (double)rand() / RAND_MAX * (high - low) + low);
	swap(a[low], a[index]);
	int temp = a[low];
	while (low < high)
	{
		while (low < high && a[high] >= temp)--high;
		a[low] = a[high];
		while (low < high && a[low] <= temp)++low;
		a[high] = a[low];
	}
	a[low] = temp;
	return low;
}

int RandSelect(int a[], int low, int high, int K)
{
	if (low == high) return a[low];
	int pivotpos = RandPartition(a, low, high);//随机选中的元素最终位置
	int rank = pivotpos - low + 1;//从1开始
	if (K == rank) return a[pivotpos];
	else if (K < rank) return RandSelect(a, low, pivotpos - 1, K);
	else return RandSelect(a, pivotpos + 1, high, K - rank);
}
int main()
{
	srand((unsigned)time(NULL));
	int a[9] = { 0,6,5,4,2,8,7,1,3 };
	cout << RandSelect(a, 1, 8, 2);
	要从1开始。不然随即元素的位置和总排名对不上,很麻烦。
	
	cout << RandSelect(a, 1, 8, 8/2);
	将字符串分为前后差最大的两部分
}

最大公约数

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值