二分查找:
- 拓展:精度問題
- 木棒切割
- 快速冪
歸併排序:
- 非遞歸實現
二分
基於有序序列
的查找算法
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);
將字符串分爲前後差最大的兩部分
}