Print Longest Common Subsequence
Solve this ProblemTest Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
0 ≤ text1.length, text2.length ≤ 12 - ◆
text1 and text2 consist only of lowercase English letters - ◆
If more than one longest common subsequence exists, return the one produced by preferring to move up (skip a character of text1) over moving left whenever both directions tie
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Recursive Backtrack After Building the DP Table
OptimalFirst fill the same length-only dp[i][j] table used for the length variant of this problem: for every prefix pair, either extend the diagonal on a matching tail character or carry forward the better of the two neighboring prefixes. Once the table is complete, walk it backward from the bottom-right corner with a small recursive helper. A matching tail character is always part of the answer, so the helper recurses one step closer to the base case and appends that character only after the recursive call returns — which naturally places every matched character in the correct left-to-right order. When the tail characters differ, the helper follows whichever neighboring cell holds the larger value, preferring the cell above when both are equal.
O(n·m)O(n·m)1class Solution {
2 public String printLCS(String text1, String text2) {
3 int n = text1.length(), m = text2.length();
4 int[][] dp = new int[n + 1][m + 1];
5 for (int i = 1; i <= n; i++) {
6 for (int j = 1; j <= m; j++) {
7 if (text1.charAt(i - 1) == text2.charAt(j - 1)) {
8 dp[i][j] = dp[i - 1][j - 1] + 1;
9 } else {
10 dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
11 }
12 }
13 }
14 return backtrack(dp, text1, text2, n, m);
15 }
16
17 private String backtrack(int[][] dp, String text1, String text2, int i, int j) {
18 if (i == 0 || j == 0) return "";
19 if (text1.charAt(i - 1) == text2.charAt(j - 1)) {
20 return backtrack(dp, text1, text2, i - 1, j - 1) + text1.charAt(i - 1);
21 }
22 if (dp[i - 1][j] >= dp[i][j - 1]) {
23 return backtrack(dp, text1, text2, i - 1, j);
24 }
25 return backtrack(dp, text1, text2, i, j - 1);
26 }
27}Iterative Backtrack After Building the DP Table
OptimalBuild the exact same dp[i][j] length table bottom-up. Then, instead of recursing, walk it with a simple loop: start two pointers at the bottom-right corner and step through the table one cell at a time. A matching tail character gets collected and both pointers move diagonally inward; otherwise the pointer moves toward whichever neighboring cell holds the larger value, favoring the upward move on a tie. Because this walk visits characters from the end of the subsequence toward its start, the collected characters come out backward and are reversed once at the end before being returned.
O(n·m)O(n·m)1class Solution {
2 public String printLCS(String text1, String text2) {
3 int n = text1.length(), m = text2.length();
4 int[][] dp = new int[n + 1][m + 1];
5 for (int i = 1; i <= n; i++) {
6 for (int j = 1; j <= m; j++) {
7 if (text1.charAt(i - 1) == text2.charAt(j - 1)) {
8 dp[i][j] = dp[i - 1][j - 1] + 1;
9 } else {
10 dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
11 }
12 }
13 }
14 StringBuilder sb = new StringBuilder();
15 int i = n, j = m;
16 while (i > 0 && j > 0) {
17 if (text1.charAt(i - 1) == text2.charAt(j - 1)) {
18 sb.append(text1.charAt(i - 1));
19 i--;
20 j--;
21 } else if (dp[i - 1][j] >= dp[i][j - 1]) {
22 i--;
23 } else {
24 j--;
25 }
26 }
27 return sb.reverse().toString();
28 }
29}