From b5f956c45e801203af0f2c7505988ac04cfd9453 Mon Sep 17 00:00:00 2001 From: BrianLusina <12752833+BrianLusina@users.noreply.github.com> Date: Tue, 14 Nov 2023 06:09:48 +0300 Subject: [PATCH 1/3] feat(backtracking): permutations --- {pystrings => algorithms/backtracking}/permutations/__init__.py | 0 .../backtracking}/permutations/generate_permutations/README.md | 0 .../backtracking}/permutations/generate_permutations/__init__.py | 0 .../generate_permutations/test_generate_permutations.py | 0 .../permutations/lexicographic_permutations/README.md | 0 .../permutations/lexicographic_permutations/__init__.py | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename {pystrings => algorithms/backtracking}/permutations/__init__.py (100%) rename {pystrings => algorithms/backtracking}/permutations/generate_permutations/README.md (100%) rename {pystrings => algorithms/backtracking}/permutations/generate_permutations/__init__.py (100%) rename {pystrings => algorithms/backtracking}/permutations/generate_permutations/test_generate_permutations.py (100%) rename {pystrings => algorithms/backtracking}/permutations/lexicographic_permutations/README.md (100%) rename {pystrings => algorithms/backtracking}/permutations/lexicographic_permutations/__init__.py (100%) diff --git a/pystrings/permutations/__init__.py b/algorithms/backtracking/permutations/__init__.py similarity index 100% rename from pystrings/permutations/__init__.py rename to algorithms/backtracking/permutations/__init__.py diff --git a/pystrings/permutations/generate_permutations/README.md b/algorithms/backtracking/permutations/generate_permutations/README.md similarity index 100% rename from pystrings/permutations/generate_permutations/README.md rename to algorithms/backtracking/permutations/generate_permutations/README.md diff --git a/pystrings/permutations/generate_permutations/__init__.py b/algorithms/backtracking/permutations/generate_permutations/__init__.py similarity index 100% rename from pystrings/permutations/generate_permutations/__init__.py rename to algorithms/backtracking/permutations/generate_permutations/__init__.py diff --git a/pystrings/permutations/generate_permutations/test_generate_permutations.py b/algorithms/backtracking/permutations/generate_permutations/test_generate_permutations.py similarity index 100% rename from pystrings/permutations/generate_permutations/test_generate_permutations.py rename to algorithms/backtracking/permutations/generate_permutations/test_generate_permutations.py diff --git a/pystrings/permutations/lexicographic_permutations/README.md b/algorithms/backtracking/permutations/lexicographic_permutations/README.md similarity index 100% rename from pystrings/permutations/lexicographic_permutations/README.md rename to algorithms/backtracking/permutations/lexicographic_permutations/README.md diff --git a/pystrings/permutations/lexicographic_permutations/__init__.py b/algorithms/backtracking/permutations/lexicographic_permutations/__init__.py similarity index 100% rename from pystrings/permutations/lexicographic_permutations/__init__.py rename to algorithms/backtracking/permutations/lexicographic_permutations/__init__.py From 368dc20e823267893eeeda05fa9784df7e7454d8 Mon Sep 17 00:00:00 2001 From: BrianLusina <12752833+BrianLusina@users.noreply.github.com> Date: Tue, 14 Nov 2023 06:41:23 +0300 Subject: [PATCH 2/3] feat(dp): longest common subsequence --- .../longest_common_subsequence/README.md | 39 +++++++++++++++++++ .../longest_common_subsequence/__init__.py | 20 ++++++++++ .../test_longest_common_subsequence.py | 32 +++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 algorithms/dynamic_programming/longest_common_subsequence/README.md create mode 100644 algorithms/dynamic_programming/longest_common_subsequence/__init__.py create mode 100644 algorithms/dynamic_programming/longest_common_subsequence/test_longest_common_subsequence.py diff --git a/algorithms/dynamic_programming/longest_common_subsequence/README.md b/algorithms/dynamic_programming/longest_common_subsequence/README.md new file mode 100644 index 00000000..5171f8ee --- /dev/null +++ b/algorithms/dynamic_programming/longest_common_subsequence/README.md @@ -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 diff --git a/algorithms/dynamic_programming/longest_common_subsequence/__init__.py b/algorithms/dynamic_programming/longest_common_subsequence/__init__.py new file mode 100644 index 00000000..be42b877 --- /dev/null +++ b/algorithms/dynamic_programming/longest_common_subsequence/__init__.py @@ -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] diff --git a/algorithms/dynamic_programming/longest_common_subsequence/test_longest_common_subsequence.py b/algorithms/dynamic_programming/longest_common_subsequence/test_longest_common_subsequence.py new file mode 100644 index 00000000..eeeab261 --- /dev/null +++ b/algorithms/dynamic_programming/longest_common_subsequence/test_longest_common_subsequence.py @@ -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() From 74dba5200478c8cadac48c18254c37356688ac50 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Tue, 14 Nov 2023 03:41:51 +0000 Subject: [PATCH 3/3] updating DIRECTORY.md --- DIRECTORY.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 464f179a..f783f918 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -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 @@ -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 @@ -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 @@ -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)