二分:精確二分;分割木棒;快速冪;隨機數排序算法

二分查找:

歸併排序:

  • 非遞歸實現

二分

基於有序序列的查找算法

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);
	將字符串分爲前後差最大的兩部分
}

最大公約數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章