/*最长上升子序列问题 LIS
有一个长为N的数列A0,A1,A2,……An-1
请求出这个序列中最长的上升子序列长度
上升子序列是指的对于任意的i<j 都有Ai<Aj
EG:
输入:N=5
A={4,2,3,1,5}
输出3 //<2,3,5>
解 动态规划:
定义DP[i]为以Ai为末尾的最长上升子序列长度
则 DP[i]为
只包含Ai的子序列
或者
在满足子长上升子序列的要求上 追加Ai到末尾得到长度增加的LIS
∴ DP[i]=MAX(1 , DP[j]+1【 i<j&&Ai<Aj 】)
时间复杂度O(N^2)
*/
# include <stdio.h>
# define MAX(a,b) ((a)>(b)?(a):(b))
# define S 100
int main(){
int A[S]={0},DP[S]={0},sum=1,N,i,j,B[S]={0},k=0;
scanf("%d",&N);
for(i=0;i<N;i++)
scanf("%d",&A[i]);
for(i=0;i<N;i++)
{
DP[i]=1;
for(j=0;j<i;j++)
if(A[j]<A[i])
DP[i]=MAX(DP[i],DP[j]+1);
sum=MAX(sum,DP[i]);
}
printf("%d",sum);
return 0;
}
说到字符串匹配,这是一个老但是热度不减的话题
也是学数据结构必须要会的
代码--如果不写注释 几乎不会有人看
虽然是学计算机的 前方的路对我来说还比较迷茫
只能是---》漫天撒网抓蝴蝶---low漏陋
经过半个小时的复习 整理 想着能将代码简洁化 又不失条理
将KMP和BF的写在一起 就当做个比较吧
这种经典算法 不需要解释 至于将代码简洁化
我想 大概人人都想自己做 而且自己做出来的才有意义 别人做的除非很好 否则很难看的下去
另外 做的字符串替换 链接:字符串替换-循环
# include <stdio.h>
# include <stdlib.h>
# define N 101 //用户输入的字符串长度最大值为N-1 第N个存'\0'
# define M 2 //用户输入的字符串长度最小值
int BF(char a[],char b[]);//BF算法 a为主串,b为被检验的串返回匹配的下标 若无返回0
int KMP(char *A,char *B);//比BF复杂度低 和BF功能相同
int gainchar(char *a,int min,int max);//模拟strlen类 对*a输入范围[min,max-1]返回字符串长度,不影响下一级输入
int main(){
char A[N],B[N];
int len;
printf("请输入A字符串(%d---%3d):\n",M,N-1);
len=gainchar(A,M,N);
printf("请输入B字符串(%d---%3d):\n",1,len);
gainchar(B,1,len+1);
printf("注:匹配失败返回0!\n\n主串:%s\n次串:%s\nBF:匹配的位置:%d\nKMP匹配的位置:%d",A,B,BF(A,B),KMP(A,B));
return 0;
}
int gainchar(char *a,int min,int max)//对*a输入范围[min,max-1] 防止数组超界 并清除缓冲区
{
int c,k;
do{
c=-1;k=0;
fgets(a,max,stdin);
while(a[++c]);
c=a[c-1]=='\n'&&c<max?c-1:c;
if(c>=max-1)
while(getchar()!='\n')
k++;
else
a[c]='\0';
if(k||c&&(c>max||c<min))//如果用户只输入'\n'则不提示输入错误,否则提示错误
printf("输入长度有误,请重新输入!\n注:只录入(%d--%d)字节:\n",min,max-1);
}while(k||c<min);
return c;
}
int KMP(char *A,char *B)//经典算法 已经简洁化 复杂度 o(strlen(A)+strlen(B))
{
int i=1,j=0,C=-1,*Q=NULL;
while(B[++C]); //求主串A的长度
Q=(int *)calloc(C,sizeof(int));//申请内存存NEXVAL的值
while(i<C) //获得模式串的NEXTVAL数组
if(!j||B[i]==B[j])
{
++j;
++i;
Q[i]=(B[i]-B[j]?j:Q[j]);
}
else
j=Q[j];
i=j=0; //开始和主串匹配
while (A[i]&&B[j])
if (A[i++]==B[j])
j++;
else
j=Q[j];
return B[j]?0:i-j+1; //返回下标值
}
int BF(char a[],char b[])//BF算法 一般o(strlen(A)+strlen(B)) 最坏o(strlen(A)*strlen(B))
{
int i=0,j=0;
while (a[i]&&b[j])
if (a[i++]==b[j]) // 如果匹配成功 继续比较后继字
++j;
else //否则 主串回溯
{
i-=j;
j=0;
}
return b[j]?0:i-j+1; //返回下标
}
附加小程序:
/*
辗转相除法(拓展欧几里得算法): 复杂度 最差O(log[max(a,b)])
假设gys(a,b) 是计算a,b 的最大公因数的函数‘
设 a/b得到的商和余数 分别为 p q
则 a=b*p +q;
所以 gys(b,q) 即整除a也整除b 所以gys(b,q)整除gys(a,b)
又q=a-b*p 同理可证 gys(a,b)整除gys(b,q)
综上 gys(a,b)=gys(b,q) 即 gys(a,b)=gys(b,a%b)
由于第二个形参是不断地减少的
所以 最终 gys(a,b)-->gys(c,0) 此时的c即为最大公因数
*/
# include <stdio.h>
int gys(int a,int b);//递归算法
int GYS(int m,int n);//非递归算法
int main(){
int A=45,B=24;
printf("%d %d的最大公因数\n递归: %d\n非递归:%d\n",A,B,gys(A,B),GYS(A,B));
printf("最小公倍数\n递归: %d\n非递归:%d",A*B/gys(A,B),A*B/GYS(A,B));
return 0;
}
int gys(int a,int b)//递归算法
{
return b?gys(b,a%b):a;
}
int GYS(int m,int n)//非递归算法
{
int A,B;
if(n>m)
{
A=m;m=n;n=A;
}
while((B=m%n)!=0)
{
m=n;n=B;
}
return n;
}