二分查找:
- 拓展:精度问题
- 木棒切割
- 快速幂
归并排序:
- 非递归实现
二分
基于有序序列
的查找算法
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%2
和 b&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);
将字符串分为前后差最大的两部分
}