For the general case of an arbitrary number of input sequences, the problem is NP-hard. When the number of sequences is constant, the problem is solvable in polynomial time by dynamic programming.
The LCS problem has an optimal substructure: the problem can be broken down into smaller, simpler subproblems, which can in turn be broken down into simpler subproblems, and so on, until, finally, the solution becomes trivial. LCS in particular has overlapping subproblems: the solutions to high-level subproblems often reuse solutions to lower level subproblems. Problems with these two properties are amenable to dynamic programming approaches, in which subproblem solutions are memoized, that is, the solutions of subproblems are saved for reuse.
// finding the LCS for (LCS = 0, i = 0; i < m; i++) { for (j = 0; matchlist[stringA[i]][j] != -1; j++) { // if the number bigger then the biggest number in the L, LCS + 1 if (matchlist[stringA[i]][j] > L[LCS]) { LCS++; L[LCS] = matchlist[stringA[i]][j]; } // else, do the binary search to find the place to insert the number else { high = LCS; low = 0; k = 0; while (true) { mid = low + ((high - low) / 2); if (L[mid] == matchlist[stringA[i]][j]) { k = 1; break; } if (high - low <= 1) { mid = high; break; } if (L[mid] > matchlist[stringA[i]][j]) { high = mid; } elseif (L[mid] < matchlist[stringA[i]][j]) { low = mid; } } if (k == 0) { L[mid] = matchlist[stringA[i]][j]; } } } } return LCS; } }
Submission Detail
43 / 43 test cases passed.
Runtime: 12 ms, faster than 32.13% of Java online submissions for Longest Common Subsequence.
Memory Usage: 39.2 MB, less than 92.10% of Java online submissions for Longest Common Subsequence.
Dynamic Programming
bottom-up approach
Oftentimes I found Wikipedia is helpful when doing leetcode algorithm problems.
classSolution { publicintlongestCommonSubsequence(String text1, String text2) { finalintLEN1= text1.length(), LEN2 = text2.length(); Map<String, Integer> map = newHashMap<String, Integer>(); return lcsLength(text1, text2, LEN1, LEN2, map); } privateintlcsLength(String X, String Y, int m, int n, Map<String, Integer> lookup) { // return if we have reached the end of either string if (m == 0 || n == 0) return0;
// construct an unique map key from dynamic elements of the input Stringkey= m + "|" + n;
// if sub-problem is seen for the first time, solve it and // store its result in a map if (!lookup.containsKey(key)) { // if last character of X and Y matches if (X.charAt(m - 1) == Y.charAt(n - 1)) { lookup.put(key, lcsLength(X, Y, m - 1, n - 1, lookup) + 1);
} else { // else if last character of X and Y don't match lookup.put(key, Integer.max(lcsLength(X, Y, m, n - 1, lookup), lcsLength(X, Y, m - 1, n, lookup))); } }
// return the subproblem solution from the map return lookup.get(key); } }
Submission Detail
43 / 43 test cases passed.
Runtime: 295 ms, faster than 5.04% of Java online submissions for Longest Common Subsequence.
Memory Usage: 167 MB, less than 5.04% of Java online submissions for Longest Common Subsequence.