**
**
*算法的特性:
1、输入。0个或多个输入
2、输出。至少一个输入
3、确定性。每条指令不能模糊
4、有限行。执行次数、运行时间有限
*程序的特性:
除去4,其他和算法一样。
例如,操作系统,它是一个无限循环的程序,虽然不能叫做算法,但是可以是程序。操作系统中的每一个子操作,却可以叫做算法。
算法的复杂性 取决于 所需资源的多少。资源包括时间和空间,所以,算法的复杂性可以分为:
1、时间复杂性(主要考虑)
2、空间复杂性
用N表示:问题的规模
用I表示 :输入
用A表示:算法本身
用C表示复杂性,则C = F(N, I, A)
对同一个算法A可隐去,所以C = F(N, I)
由于输入I的不同,会导致算法的复杂度不同。可以分为最坏Tmax(N),平均Tavg(N),最好Tmin(N),一般使用最坏情况Tmax(N)作为度量
真实的算法中,许多复杂的算法无法对每一个运算都进行计算,所以,采用渐进复杂度代替。
1、O代表上界。例如N² = O(N³)
2、Ω代表下界。例如N² = Ω(N)
3、θ代表上界和下界相等。N² = θ(N²)
int func(int n){
if(n==0) return 1;
return n*func(n-1);
}
int func(int n){
if(n<=1) return 1;
return func(n-1)+func(n-2);
}
int func(int n, int m){
// n表示要分解的数字,最大的加数不能超过m
if(m < 1|| n < 1) return 0;
if(m==1|| n==1) return 1;
if(n<m) return q(n, n);// 最大加数不能大于n
if(n==m) return func(n,m-1)+1; // 最大加数等于它本身
return func(n-1,m)+func(n,m-1);
}
void func(int n, int a, int b, int c){
if(n>0){
func(n-1, a, c, b);//将a上的1~n-1号盘子移动到c,借助b
move(a, b); //将a上剩下的最大的n号盘子移动到b
func(n-1, c, b, a);//将c上的1~n-1号盘子移动到b,借助a
}
}
重点:全排列。
1、思路:设R = {r1, r2, r3, …… rn},则全排列
Perm(R)=(r1)Perm(R - r1)+(r2)Perm(R - r2)+……+(rn)Perm(R - rn)
即,每一个集合R的全排列等于集合R减掉rk后等到的这个集合R’的全排列加上rk
2、算法:
// 排列从head到end的元素
Perm(int list[], int head, int end){
if(head==end){
for(int i=0;i<end;i++)
cout<<list[i];
cout<<endl;
}
// head这个位置可以放的元素有(end-head+1)种可能
for(int i=head;i<=end;i++){
swap(list[head], list[i]);
Perm(list, head+1, end);
swap(list[head], list[i]);
}
}
设矩阵A、B是n阶矩阵,AB中,每个元素需要n次乘法和n-1次加法,所以n²个元素时间复杂度为O(n³)
strassen矩阵乘法是将A,B分别分为四个更小的矩阵A11 A12 和 B11 B12,
A21 A22 B21 B22
可以得出:AB = A11B11+A21B12 A11B12+A12B22
A21B11+A22B21 A21B12+A22B22
时间复杂度仍然是O(n³)
void qsort(int a[], int h, int t){
if(h<t){
int r = departion(a, h, t);
qsort(a, h, r-1);
qsort(a, r+1, t);
}
}
int departion(int a[], int h, int t){
int r = h;
while(true){
while(h<t&&a[++h]<=a[r]) ;
while(a[t]>a[r]) t--;
if(h<t) swap(a[t],a[h]);
else break;
}
swap(a[r],a[t]);
return r;
}
//选出第K小的数,最坏复杂度O(n²),但平均时间复杂度还行
int solve(int a[], int h, int t, int k){
if(h==t) return a[h];
int i = partion(a, h, t); //该方法把数组a划分为两个段,a[h,i-1]a[i+1,t]
int j = i - h + 1;
if(j>=k) return solve(a, h, i, k);
else return solve(a, i+1, t, k -j);
}
// 优化算法,思路:线性时间内找到一个划分基准。最坏时间复杂度O(N)
//伪代码
int solve(int a[], int h, int t, int k){
if(t - h < 75){
用随便一个简单的排序算法对a[h]-a[t]从小到大排序;
return a[h+k-1];
}
for(int i=0; i<=(t-h-4)/5; i++){
将a[p+i*5]-a[p+i*5+4]的第3小元素与a[i]交换位置;
}//此时前(t-h-4)/5项全都是各个组的中位数
int x = solve(a, h, h+(t-h-4)/5, (t-h-4)/10); //找出中位数的中位数,作为基准元素
int i = partion(a, h, t, x); //以x为基准,划分a[h]-a[t],小的放左段,大的放右段
int j = i - h + 1;
if(k <= j) return solve(a, h, i, k);
else return solve(a, i+1, t, k - j);
}
void MatrixChain(int *p,int n,int **m,int **s)
{
for (int i = 1; i <= n; i++) m[i][i] = 0;
for (int r = 2; r <= n; r++)
for (int i = 1; i <= n - r+1; i++) {
int j=i+r-1;
// Ai到j所需的最少数乘次数假设为A[i](A[i+1]…A[j])的数乘次数
m[i][j] = m[i+1][j]+ p[i-1]*p[i]*p[j];
s[i][j] = i;//括号的位置
for (int k = i+1; k < j; k++) {
//逐一计算,找到最佳断法
int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];
if (t < m[i][j]) { m[i][j] = t; s[i][j] = k;}
}
}
}
void solve(int m, int n, int *x, int *y, int **c, int **b){
// m,n为两个字符串x,y的长度
// c[i][j]保存x[0,i]和y[0,j]最长子串的长度,b[i][j]记录来向,方便回溯输出子串
for(int i=0;i<=m;i++) c[i][0]=0;
for(int i=0;i<=n;i++) c[0][n]=0;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(x[i]==y[j]){
c[i][j]=[i-1][j-1]+1;
b[i][j]=1;
}
else{
if(c[i-1][j]>=c[i][j-1]){
c[i][j]=c[i-1][j];
b[i][j]=2;
}
else {
c[i][j]=c[i][j-1];
b[i][j]=3;
}
}
}
}
}
// 递归回溯子串
void print(int i, int j, int *x, int **b){
if(i<=0||j<=0) return;
if(b[i][j]==1){
print(i-1,j-1,x,b);
cout<<x[i];
}
else if(b[i][j]==2){
print(i-1,j,x,b);
}
else{
print(i,j-1,x,b);
}
}
// a[]是字符串,b[j]记录以a[j]为最后一个字符的最大子段和
void solve(int n, int *a, int *b){
b[1]=max(0,a[1]);
for(int j=2;j<=n;j++){
b[j] = max(b[j-1]+a[j], a[j]);
}
}
重点
重点
重点
如果帮到你的话,点个关注不迷路~
至少至少点个赞吧 ~ 客官~ (ಥ_ಥ)