【最长上升子序列】
输出长度
O(n*n)
while(scanf("%s%s",s1+1,s2+1)!=EOF)
{
l1 = strlen(s1+1);
l2 = strlen(s2+1);
for(i = 0; i <= l1;i ++)
f[i][0] = 0;
for(i = 0; i <= l2; i ++)
f[0][i] = 0;
for(i = 1; i <= l1; i ++)
{
for(j = 1; j <= l2; j ++)
{
if(s1[i] == s2[j])//字符相等时,上一个状态长度加1
f[i][j] = f[i-1][j-1] + 1;
else
{//字符不等时,取最大的字符序列公共长度
if(f[i-1][j] > f[i][j-1])
f[i][j] = f[i-1][j];
else
f[i][j] = f[i][j-1];
}
}
}
printf("%d\n",f[l1][l2]);
}
O(nlogn)
int find(int flag,int *end,int low,int high)
{//二分法查找end中最小的小于数flag的下标
int mid;
while(low < high)
{
mid = (low+high)>>1;
if(flag > end[mid])
low = mid + 1;
else
high = mid;
}
return low;
}
int main()
{//end数组存储的是子序列长度为i的最小尾数
end[1] = num[1],len = 1;//len记录子序列最长长度
for(i = 2; i <= n; i ++)
{
if(num[i] > end[len])//如果求非递减的序列则加上等号
ans = ++len;
else
ans = find(num[i],end,1,len+1);
end[ans] = num[i];
}
printf("%d\n",len);
}
回溯输出最长上升子序列 O(n*n)
void LCS(char *x,char *y,int n,int m,int a[][N+10],int b[][N+10] )
{//找到最长公共子序列
for(i = 0; i <= n; i ++)
a[i][0] = 0;
for(j = 0; j <= m; j ++)
a[0][j] = 0;
for( i = 1; i <= n; i ++)
for( j = 1; j <= m; j ++)
{
if(x[i-1] == y[j-1])
{//下标从0开始,故为i-1,j-1。
a[i][j] = a[i-1][j-1]+1;
b[i][j] = 1; //字符相等标记为1
}
else
{
if( a[i-1][j] > a[i][j-1])
{
a[i][j] = a[i-1][j] ;
b[i][j] = 0;//字符串1大标记为0
}
else
{
a[i][j] = a[i][j-1] ;
b[i][j] = -1;//字符串2大标记为1
}
}
}
return;
}
void PrintLcs(char *s,int n,int m,int b[][N+10])
{//回溯输出子序列
if( 0 == n|| 0 == m)
return;
else if( b[n][m] == 1)
{
PrintLcs(s,n-1,m-1,b);
printf("%c",s[n-1]);
}
else if( b[n][m] == 0)
PrintLcs(s,n-1,m,b);
else if(b[n][m] == -1)
PrintLcs(s,n,m-1,b);
}
int main()
{
LCS(str1,str2,l1,l2,a,b);
PrintLcs(str1,l1,l2,b);
printf("\n");
return 0;
}
【最大上升子段和】
/*max_len[N]存1~n各阶段的最大上升子段和*/
max_len[1] = num[1];//数组开始的最大上升子段和是第一个元素
max = num[1];//最大上升子段和初始化
for( i = 1; i <= n; i ++)
{
num_len = 0;//记录i左边的最大上升子段和
for(j = 1; j < i; j ++)//找到i左边的最大上升子段和
{
if(num[i] > num[j])
{
if(num_len < max_len[j])
num_len = max_len[j];
}//if
} //for
max_len[i] = num_len + num[i]; //i左边最大上升子段和加上自身的值
if(max_len[i] > max)
max = max_len[i];
}//for
printf("%d\n",max); //输出最大和
【连续最大子段和】
时间复杂度为O(n),舍弃数组存储的方法原因有:1:易粗心错估数据范围,2:降低时间复杂度
1.要求输出起点和终点
#include<stdio.h>
int num[100];
int max_start,max_end;
int start,end;
int main()
{
int n,ans;
while(scanf("%d",&n)!=EOF)
{
for(int i = 1; i <= n; i ++)
scanf("%d",&num[i]);
num[0] = 0;//计算1-n的前缀和,故num[0]初始化为0
ans = num[1];//记得初值赋为数组第一个值,而不是0
start = end = 1;//初始化起始点和终止点
for(int i = 1; i <= n; i ++)//下标从1开始
{
if(num[i-1] > 0)
num[i] += num[i-1];
else
{
num[i] += 0;
start = i;//重新记录当前起点
}
if(num[i] > ans)
{
ans = num[i];
max_start = start;
max_end = i;
}
}
printf("%d %d %d\n",max_start,max_end,ans);//输出最大和,起点,终点
}
return 0;
}