Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic Programming | Longest common subsequence #59

Merged
merged 3 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
* [Test Letter Combination](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/backtracking/letter_combination/test_letter_combination.py)
* Partition String
* [Test Partition String](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/backtracking/partition_string/test_partition_string.py)
* Permutations
* Generate Permutations
* [Test Generate Permutations](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/backtracking/permutations/generate_permutations/test_generate_permutations.py)
* Bfs
* Graphs
* Dot Dsl
Expand All @@ -34,6 +37,8 @@
* [Test House Robber](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/dynamic_programming/house_robber/test_house_robber.py)
* Knapsack 01
* [Test Knapsack 01](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/dynamic_programming/knapsack_01/test_knapsack_01.py)
* Longest Common Subsequence
* [Test Longest Common Subsequence](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/dynamic_programming/longest_common_subsequence/test_longest_common_subsequence.py)
* Unique Paths
* [Test Unique Paths](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/dynamic_programming/unique_paths/test_unique_paths.py)
* Huffman
Expand Down Expand Up @@ -530,6 +535,8 @@
* [Roman Numerals](https://github.com/BrianLusina/PythonSnips/blob/master/pyregex/roman_numerals.py)

## Pystrings
* Balanced Paren
* [Test Balanced Paren](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/balanced_paren/test_balanced_paren.py)
* Domain Name
* [Extract Host](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/domain_name/extract_host.py)
* Greatest Common Divisor
Expand Down Expand Up @@ -859,7 +866,6 @@
* [Test Ascii Converter](https://github.com/BrianLusina/PythonSnips/blob/master/tests/pystrings/test_ascii_converter.py)
* [Test Autocomplete](https://github.com/BrianLusina/PythonSnips/blob/master/tests/pystrings/test_autocomplete.py)
* [Test Backspaces](https://github.com/BrianLusina/PythonSnips/blob/master/tests/pystrings/test_backspaces.py)
* [Test Balanced Paren](https://github.com/BrianLusina/PythonSnips/blob/master/tests/pystrings/test_balanced_paren.py)
* [Test Bob](https://github.com/BrianLusina/PythonSnips/blob/master/tests/pystrings/test_bob.py)
* [Test Caps Counter](https://github.com/BrianLusina/PythonSnips/blob/master/tests/pystrings/test_caps_counter.py)
* [Test Character Counter](https://github.com/BrianLusina/PythonSnips/blob/master/tests/pystrings/test_character_counter.py)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Longest Common Subsequence

Given two strings text1 and text2, return the length of their longest common subsequence. If there is no common
subsequence, return 0.

A subsequence of a string is a new string generated from the original string with some characters (can be none) deleted
without changing the relative order of the remaining characters.

For example, "ace" is a subsequence of "abcde".
A common subsequence of two strings is a subsequence that is common to both strings.

Example 1:

```text
Input: text1 = "abcde", text2 = "ace"
Output: 3
Explanation: The longest common subsequence is "ace" and its length is 3.
```

Example 2:

```text
Input: text1 = "abc", text2 = "abc"
Output: 3
Explanation: The longest common subsequence is "abc" and its length is 3.
```

Example 3:

```text
Input: text1 = "abc", text2 = "def"
Output: 0
Explanation: There is no such common subsequence, so the result is 0.
```

## Related Topics

- String
- Dynamic Programming
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
def longest_common_subsequence(text1: str, text2: str) -> int:
"""LCS is a classic problem. Let dp[i][j] be the LCS for string text1 ends at index i and string text2 ends at index
j. If text1[i]==text2[j], then dp[i][j] would be 1+dp[i−1][j−1]. Otherwise, we target the largest LCS if we skip one
character from either text1 or text2, i.e. dp[i][j]=max(dp[i−1][j],dp[i][j−1]).

Complexity:
Where m is the length of text1 and n is the length of text2
- Time complexity: O(m*n)
- Space complexity: O(m*n)
"""
dp = [[0 for _ in range(len(text2) + 1)] for _ in range(len(text1) + 1)]

for i in range(len(text1) - 1, -1, -1):
for j in range(len(text2) - 1, -1, -1):
if text1[i] == text2[j]:
dp[i][j] = 1 + dp[i + 1][j + 1]
else:
dp[i][j] = max(dp[i + 1][j], dp[i][j + 1])

return dp[0][0]
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import unittest
from . import longest_common_subsequence


class LongestCommonSubsequenceTestCase(unittest.TestCase):
def test_abcde_ace_returns_3(self):
"""should return 3 for text1='abcde' and text2='ace'"""
text1 = 'abcde'
text2 = 'ace'
expected = 3
actual = longest_common_subsequence(text1, text2)
self.assertEqual(expected, actual)

def test_abc_abc_returns_3(self):
"""should return 3 for text1='abc' and text2='abc'"""
text1 = 'abc'
text2 = 'abc'
expected = 3
actual = longest_common_subsequence(text1, text2)
self.assertEqual(expected, actual)

def test_abc_def_returns_0(self):
"""should return 0 for text1='abc' and text2='def'"""
text1 = 'abc'
text2 = 'def'
expected = 0
actual = longest_common_subsequence(text1, text2)
self.assertEqual(expected, actual)


if __name__ == '__main__':
unittest.main()
Loading