1、master公式的使用
T ( N ) = a ∗ T ( N / b ) + O ( N d ) T(N) = a * T(N / b) + O(N ^ d)\\ T(N)=a∗T(N/b)+O(Nd)
T(N):母问题的规模
T(N/b):子问题的规模
a:调用次数
O(N^d):除去子问题,剩下操作的时间复杂度
-
logb a > d --> 复杂度为O(Nlogb a)
-
logb a = d --> 复杂度为O(Nd * log N)
-
logb a < d --> 复杂度为O(Nd)
2、归并排序(时间:O(N log N) 空间:O(N): 没有浪费比较行为)
#include<stdio.h>
int a[10] = {4,3,6,2,1,5,7,10,9,8};
void marge(int arr[], int l, int mid, int r){
int b[r - l + 1];
int i = 0;
int p1 = l;
int p2 = mid + 1;
while(p1 <= mid && p2 <= r){
b[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
while(p1 <= mid){
b[i++] = arr[p1++];
}
while(p2 <= r){
b[i++] = arr[p2++];
}
for(int j = 0; j < i; j++){
arr[l + j] = b[j];
}
}
void process(int arr[], int l, int r){
if(l == r){
return;
}
int mid = l + r >> 1;
process(arr, l, mid);
process(arr, mid + 1, r);
marge(arr, l, mid, r);
}
int main(){
process(a, 0, 9);
for(int i = 0; i < 10; i++){
printf("%d ", a[i]);
}
return 0;
}
3、小和问题 与 逆序对问题。
小和问题因为要先放右侧的子数组,所以丧失了归并排序的稳定性。
#include<stdio.h>
int a[5] = {1,2,3,4,5};
int marge(int arr[], int l, int mid, int r){
int b[r - l + 1];
int i = 0;
int p1 = l;
int p2 = mid + 1;
int res = 0;
while(p1 <= mid && p2 <= r){
//就加了这么一条语句
res += arr[p1] < arr[p2] ? (r - p2 + 1) * arr[p1] : 0;
b[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
while(p1 <= mid){
b[i++] = arr[p1++];
}
while(p2 <= r){
b[i++] = arr[p2++];
}
for(int j = 0; j < i; j++){
arr[l + j] = b[j];
}
return res;
}
int process(int arr[], int l, int r){
if(l == r){
return 0;
}
int mid = l + r >> 1;
return process(arr, l, mid) + process(arr, mid + 1, r) + marge(arr, l, mid, r);
}
int main(){
int x = process(a, 0, 4);
printf("%d\n", x);
for(int i = 0; i < 5; i++){
printf("%d ", a[i]);
}
return 0;
}
4、荷兰国旗问题(时间复杂度O(N log N) 空间复杂度O(1))
给定一个数组arr
,和一个数num
,请把小于等于num
的数放在数组的左边,等于num
的数放在数组的中间, 大于num
的数放在数组的右边。
思路:
arr[i] < num
,arr[i]
和 小区下一个交换,小区范围右扩一位,i++
arr[i]
==num
,i++
arr[i] > num
,arr[i]
和大区前一个交换,大区范围左扩一位,i
原地不变
循环停止条件:当 i
包含在大区范围内
5、快速排序(最差O(log N2),平均O(N log N)
1、1.0版本
先把最后一个数x提出来,剩余的数把小于x放左边,大于x放右边,递归
2、2.0版本
先把最后一个数x提出来,剩余的数把小于x放左边,等于x的放中间,大于x放右边,递归
#include<stdio.h>
int arr[5] = {4,2,1,3,5};
int lr[2];
void swap(int arr[], int l, int r){
int temp;
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
}
void parttion(int arr[], int l, int r){
//小于区的左边界
int p1 = l - 1;
//大于区的右边界,最后一个数是划分值
int p2 = r;
int p = l;
while(p < p2){
if(arr[p] < arr[r]){
swap(arr, p++, ++p1);
}else if(arr[p] > arr[r]){
swap(arr, p, --p2);
}else{
p++;
}
}
swap(arr, r, p2);
lr[0] = p1;
lr[1] = p2 + 1;
}
void process(int arr[], int l, int r){
if(l < r){
parttion(arr, l, r);
process(arr, l, lr[0]);
process(arr, lr[1],r);
}
}
int main(){
process(arr, 0, 4);
for(int i = 0; i < 5; i++){
printf("%d ", arr[i]);
}
return 0;
}
3、3.0版本
随机选出一个数与最后一个数交换,用这个数来做,这样概率就相等了。