diff --git a/algorithms/dynamic_programming/print_all_longest_common_subsequence.py b/algorithms/dynamic_programming/print_all_longest_common_subsequence.py new file mode 100644 index 000000000..025a7873a --- /dev/null +++ b/algorithms/dynamic_programming/print_all_longest_common_subsequence.py @@ -0,0 +1,62 @@ +""" +Find All Distinct Longest Common Subsequences + +Complexity: + Time: Exponential in the number of LCSs + Space: O(m * n) + O(number of LCSs) +""" + + +def print_all_longest_common_subsequence(s: str, t: str) -> list[str]: + """Compute all distinct longest common subsequences of two strings. + + Args: + s: First string. + t: Second string. + + Returns: + A list containing all distinct longest common subsequences. + + Examples: + >>> print_all_longest_common_subsequence('rajroy', 'rxoyxraxj') + ['raj', 'roy'] + """ + + n, m = len(s), len(t) + dp = [[0] * (m + 1) for _ in range(n + 1)] + + for i in range(1, n + 1): + for j in range(1, m + 1): + if s[i - 1] == t[j - 1]: + dp[i][j] = 1 + dp[i - 1][j - 1] + else: + dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + + res = set() + memo = {} + + def solve(i: int, j: int, current: str) -> None: + if i < 1 or j < 1: + res.add(current[::-1]) + return + + key = (i, j, current) + if key in memo: + res.update(memo[key]) + return + + if s[i - 1] == t[j - 1]: + solve(i - 1, j - 1, current + s[i - 1]) + else: + if dp[i - 1][j] > dp[i][j - 1]: + solve(i - 1, j, current) + elif dp[i][j - 1] > dp[i - 1][j]: + solve(i, j - 1, current) + else: + solve(i - 1, j, current) + solve(i, j - 1, current) + + memo[key] = set(res) + + solve(n, m, "") + return list(res) diff --git a/algorithms/dynamic_programming/print_any_longest_common_subsequence.py b/algorithms/dynamic_programming/print_any_longest_common_subsequence.py new file mode 100644 index 000000000..455e1561c --- /dev/null +++ b/algorithms/dynamic_programming/print_any_longest_common_subsequence.py @@ -0,0 +1,52 @@ +""" +Print any longest common subsequence + +Complexity: + Time: O(n * m) + Space: O(n * m) +""" + + +def print_any_longest_common_subsequence(s1: str, s2: str) -> str: + """Return any one longest common subsequence of two strings. + + Args: + s1: First string. + s2: Second string. + + Returns: + A string representing any one longest common subsequence. + + Example: + >>> print_any_longest_common_subsequence('rajroy', 'rxoyxraxj') + "raj" or "roy" + """ + + n = len(s1) + m = len(s2) + dp = [[0] * (m + 1) for _ in range(n + 1)] + + for ind1 in range(1, n + 1): + for ind2 in range(1, m + 1): + if s1[ind1 - 1] == s2[ind2 - 1]: + dp[ind1][ind2] = 1 + dp[ind1 - 1][ind2 - 1] + else: + dp[ind1][ind2] = max(dp[ind1 - 1][ind2], dp[ind1][ind2 - 1]) + + length = dp[n][m] + i, j = n, m + lcs_str = [""] * length + index = length - 1 + + while i > 0 and j > 0: + if s1[i - 1] == s2[j - 1]: + lcs_str[index] = s1[i - 1] + index -= 1 + i -= 1 + j -= 1 + elif dp[i - 1][j] > dp[i][j - 1]: + i -= 1 + else: + j -= 1 + + return "".join(lcs_str)