对 LCS 和 LIS 的总结

<一>LCS的常规思路:

View Code
 1 //dp[x][y]的状态表示ary1[]的前x个数,ary2[]的前y个数中的最长公共子序列
 2 //O(n*m),n为ary1[]的长度,m为ary2的长度
 3 
 4 int dp[SIZE][SIZE];
 5 int ary1[SIZE],ary2[SIZE];
 6 
 7 for(int i=1; i<=n; i++)
 8 {
 9     for(int j=1; j<=m; j++)
10     {
11         if(ary1[i] == ary2[j])
12             dp[i][j] = dp[i-1][j-1] + 1;
13         else 
14             dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
15     }
16 }

有时需要记录路径,只需加一个递归函数即可

View Code
 1 //dp[x][y]的状态表示ary1[]的前x个数,ary2[]的前y个数中的最长公共子序列
 2 //O(n*m),n为ary1[]的长度,m为ary2的长度
 3 
 4 int dp[SIZE][SIZE];
 5 int ary1[SIZE],ary2[SIZE];
 6 int path[SIZE][SIZE];//初始化为0
 7 
 8 void printPath(int x,int y)
 9 {
10     if(path[x][y] == 0)
11         return ;
12     if(path[x][y] == 1)
13     {
14         printPath(x-1,y-1);
15         printf("%d ",ary1[x]);
16     }
17     else if(path[x][y] == 2)
18         printPath(x-1,y);
19     else
20         printPath(x,y-1);
21 }
22 
23 for(int i=1; i<=n; i++)
24 {
25     for(int j=1; j<=m; j++)
26     {
27         if(ary1[i] == ary2[j])
28         {
29             dp[i][j] = dp[i-1][j-1] + 1;
30             path[i][j] = 1;
31         }
32         else
33         {
34             dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
35             if(dp[i-1][j] > dp[i][j-1])
36                 path[i][j] = 2;
37             else
38                 path[i][j] = 3;
39         }             
40     }
41 }

 

<二>LIS的两种常规思路:

(1)O(n^2)

View Code
 1 //dp[x]表示的是到第x个数时的最长上升序列是多大
 2 //dp[]初始化为1(因为array[x]至少自己算是一个长度为1的序列
 3 //O(n^2)
 4 
 5 int dp[SIZE];
 6 int array[SIZE];
 7 
 8 for(int i=1; i<=n; i++)
 9 {
10     for(int j=1; j<=i; j++)
11     {
12         if(array[i] > array[j] && dp[i] <= dp[j])
13             dp[i] = dp[j] + 1;
14     }
15 }
16 
17 //也可以这种形式
18 for(int i=1; i<=n; i++)
19 {
20     int maxi = 0;
21     for(int j=1; j<=n; j++)
22     {
23         if(array[i] > array[j] && maxi < dp[j])
24             maxi = dp[j];
25         if(array[i] == array[j])
26             dp[j] = maxi + 1;
27     }
28 }

(2)O(n*(log(n))

View Code
 1 //dp[x]状态表示的是最长上升序列长度为x时该序列末尾的数
 2 //O(n*log(n))
 3 int dp[SIZE];
 4 int array[SIZE];
 5 
 6 dp[1] = array[1];
 7 int len = 1;
 8 for(int i=2; i<=n; i++)
 9 {
10     if(array[i] == dp[len])
11         dp[++len] = array[i];
12     else
13     {
14         int low = 1,high = len;
15         while(low <= high)
16         {
17             int mid = (low + high) >> 1;
18             if(array[i] > dp[mid])
19                 low = mid + 1;
20             else if(array[i] < dp[mid])
21                 high = mid - 1;
22             else
23             {
24                 low = mid;
25                 break;
26             }
27         }
28         dp[low] = array[i];
29     }
30 }

值得一提的是,(2)虽然在时间复杂度上更低,但是子状态的值会被更新掉,这不利于路径的打印。对于LIS的路径打印跟LCS是类似的,不再记录。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值