<一>LCS的常规思路:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
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 }
有时需要记录路径,只需加一个递归函数即可
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
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)
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
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))
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
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是类似的,不再记录。