From 849fc80a30e9e8585d0e8040dd5e77547c9901cf Mon Sep 17 00:00:00 2001 From: isatyamks Date: Mon, 7 Oct 2024 21:50:34 +0530 Subject: [PATCH 01/16] Update computer_vision/README.md with OpenCV documentation link --- computer_vision/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/computer_vision/README.md b/computer_vision/README.md index 1657128fd25e..9f935b142c08 100644 --- a/computer_vision/README.md +++ b/computer_vision/README.md @@ -8,4 +8,4 @@ Image processing and computer vision are a little different from each other. Ima While computer vision comes from modelling image processing using the techniques of machine learning, computer vision applies machine learning to recognize patterns for interpretation of images (much like the process of visual reasoning of human vision). * -* +* From daf95fad9ef8d4df789dfd010a612ffda9d50712 Mon Sep 17 00:00:00 2001 From: isatyamks Date: Mon, 7 Oct 2024 23:32:43 +0530 Subject: [PATCH 02/16] Update computer_vision/README.md with additional resource link --- computer_vision/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/computer_vision/README.md b/computer_vision/README.md index 9f935b142c08..1657128fd25e 100644 --- a/computer_vision/README.md +++ b/computer_vision/README.md @@ -8,4 +8,4 @@ Image processing and computer vision are a little different from each other. Ima While computer vision comes from modelling image processing using the techniques of machine learning, computer vision applies machine learning to recognize patterns for interpretation of images (much like the process of visual reasoning of human vision). * -* +* From df904cb55a61f089299a17de73d0e5ff194d5997 Mon Sep 17 00:00:00 2001 From: isatyamks Date: Mon, 7 Oct 2024 23:32:58 +0530 Subject: [PATCH 03/16] Add dynamic programming solutions for Longest Increasing Subsequence (LIS) and Longest Common Subsequence (LCS) --- dynamic_programming/subsequence_algorithms.py | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 dynamic_programming/subsequence_algorithms.py diff --git a/dynamic_programming/subsequence_algorithms.py b/dynamic_programming/subsequence_algorithms.py new file mode 100644 index 000000000000..256d6182a488 --- /dev/null +++ b/dynamic_programming/subsequence_algorithms.py @@ -0,0 +1,126 @@ +""" +Author : Mehdi ALAOUI + +This is a pure Python implementation of Dynamic Programming solutions to: +1. Longest Increasing Subsequence (LIS) +2. Longest Common Subsequence (LCS) + +1. LIS Problem: Given an array, find the longest increasing sub-array and return it. +Example: [10, 22, 9, 33, 21, 50, 41, 60, 80] -> [10, 22, 33, 41, 60, 80] + +2. LCS Problem: Given two sequences, find the length and content of the longest +common subsequence that appears in both of them. A subsequence appears in the +same relative order but not necessarily continuously. +Example: "programming" and "gaming" -> "gaming" +""" + +from __future__ import annotations + +# Longest Increasing Subsequence (LIS) +def longest_increasing_subsequence(array: list[int]) -> list[int]: + """ + Finds the longest increasing subsequence in the array. + + Examples: + >>> longest_increasing_subsequence([10, 22, 9, 33, 21, 50, 41, 60, 80]) + [10, 22, 33, 41, 60, 80] + >>> longest_increasing_subsequence([4, 8, 7, 5, 1, 12, 2, 3, 9]) + [1, 2, 3, 9] + >>> longest_increasing_subsequence([9, 8, 7, 6, 5, 7]) + [5, 7] + >>> longest_increasing_subsequence([1, 1, 1]) + [1] + >>> longest_increasing_subsequence([]) + [] + """ + if not array: + return [] + + # dp[i] stores the length of the LIS ending at index i + n = len(array) + dp = [1] * n + prev = [-1] * n # To reconstruct the subsequence + + max_length = 1 + max_index = 0 + + for i in range(1, n): + for j in range(i): + if array[i] > array[j] and dp[i] < dp[j] + 1: + dp[i] = dp[j] + 1 + prev[i] = j + if dp[i] > max_length: + max_length = dp[i] + max_index = i + + # Reconstructing the longest increasing subsequence + lis = [] + i = max_index + while i >= 0: + lis.append(array[i]) + i = prev[i] + if i == -1: + break + + return lis[::-1] + + +# Longest Common Subsequence (LCS) +def longest_common_subsequence(x: str, y: str) -> tuple[int, str]: + """ + Finds the longest common subsequence between two strings and its length. + + Examples: + >>> longest_common_subsequence("programming", "gaming") + (6, 'gaming') + >>> longest_common_subsequence("physics", "smartphone") + (2, 'ph') + >>> longest_common_subsequence("computer", "food") + (1, 'o') + >>> longest_common_subsequence("", "abc") + (0, '') + >>> longest_common_subsequence("abc", "") + (0, '') + >>> longest_common_subsequence("abcdef", "ace") + (3, 'ace') + """ + m, n = len(x), len(y) + dp = [[0] * (n + 1) for _ in range(m + 1)] + + for i in range(1, m + 1): + for j in range(1, n + 1): + if x[i - 1] == y[j - 1]: + dp[i][j] = dp[i - 1][j - 1] + 1 + else: + dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + + # Reconstructing the longest common subsequence + i, j = m, n + lcs = [] + while i > 0 and j > 0: + if x[i - 1] == y[j - 1]: + lcs.append(x[i - 1]) + i -= 1 + j -= 1 + elif dp[i - 1][j] > dp[i][j - 1]: + i -= 1 + else: + j -= 1 + + return dp[m][n], ''.join(reversed(lcs)) + + +if __name__ == "__main__": + import doctest + doctest.testmod() + + # Example usage for LIS + arr = [10, 22, 9, 33, 21, 50, 41, 60, 80] + lis = longest_increasing_subsequence(arr) + print(f"Longest Increasing Subsequence: {lis}") + + # Example usage for LCS + str1 = "AGGTAB" + str2 = "GXTXAYB" + length, lcs = longest_common_subsequence(str1, str2) + print(f"Longest Common Subsequence: '{lcs}' with length {length}") From 5af65ba78789cc7c84755f6850c0e244c9e08999 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:05:32 +0000 Subject: [PATCH 04/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- dynamic_programming/subsequence_algorithms.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/dynamic_programming/subsequence_algorithms.py b/dynamic_programming/subsequence_algorithms.py index 256d6182a488..6f4f4761c8b4 100644 --- a/dynamic_programming/subsequence_algorithms.py +++ b/dynamic_programming/subsequence_algorithms.py @@ -8,19 +8,20 @@ 1. LIS Problem: Given an array, find the longest increasing sub-array and return it. Example: [10, 22, 9, 33, 21, 50, 41, 60, 80] -> [10, 22, 33, 41, 60, 80] -2. LCS Problem: Given two sequences, find the length and content of the longest -common subsequence that appears in both of them. A subsequence appears in the +2. LCS Problem: Given two sequences, find the length and content of the longest +common subsequence that appears in both of them. A subsequence appears in the same relative order but not necessarily continuously. Example: "programming" and "gaming" -> "gaming" """ from __future__ import annotations + # Longest Increasing Subsequence (LIS) def longest_increasing_subsequence(array: list[int]) -> list[int]: """ Finds the longest increasing subsequence in the array. - + Examples: >>> longest_increasing_subsequence([10, 22, 9, 33, 21, 50, 41, 60, 80]) [10, 22, 33, 41, 60, 80] @@ -40,7 +41,7 @@ def longest_increasing_subsequence(array: list[int]) -> list[int]: n = len(array) dp = [1] * n prev = [-1] * n # To reconstruct the subsequence - + max_length = 1 max_index = 0 @@ -61,7 +62,7 @@ def longest_increasing_subsequence(array: list[int]) -> list[int]: i = prev[i] if i == -1: break - + return lis[::-1] @@ -107,11 +108,12 @@ def longest_common_subsequence(x: str, y: str) -> tuple[int, str]: else: j -= 1 - return dp[m][n], ''.join(reversed(lcs)) + return dp[m][n], "".join(reversed(lcs)) if __name__ == "__main__": import doctest + doctest.testmod() # Example usage for LIS From 7043442053c6dfe19f906c10c5c2cadb7f48ccc9 Mon Sep 17 00:00:00 2001 From: Satyam Kumar Date: Mon, 7 Oct 2024 23:44:36 +0530 Subject: [PATCH 05/16] Update subsequence_algorithms.py --- dynamic_programming/subsequence_algorithms.py | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/dynamic_programming/subsequence_algorithms.py b/dynamic_programming/subsequence_algorithms.py index 6f4f4761c8b4..018d4b62577d 100644 --- a/dynamic_programming/subsequence_algorithms.py +++ b/dynamic_programming/subsequence_algorithms.py @@ -20,9 +20,20 @@ # Longest Increasing Subsequence (LIS) def longest_increasing_subsequence(array: list[int]) -> list[int]: """ - Finds the longest increasing subsequence in the array. + Finds the longest increasing subsequence in the given array using dynamic programming. + + Parameters: + ---------- + array: list[int] + The input array of integers. + + Returns: + ------- + list[int] + The longest increasing subsequence (LIS) as a list. Examples: + -------- >>> longest_increasing_subsequence([10, 22, 9, 33, 21, 50, 41, 60, 80]) [10, 22, 33, 41, 60, 80] >>> longest_increasing_subsequence([4, 8, 7, 5, 1, 12, 2, 3, 9]) @@ -37,14 +48,14 @@ def longest_increasing_subsequence(array: list[int]) -> list[int]: if not array: return [] - # dp[i] stores the length of the LIS ending at index i n = len(array) - dp = [1] * n - prev = [-1] * n # To reconstruct the subsequence + dp = [1] * n # dp[i] stores the length of the LIS ending at index i + prev = [-1] * n # prev[i] stores the index of the previous element in the LIS - max_length = 1 - max_index = 0 + max_length = 1 # Length of the longest increasing subsequence found + max_index = 0 # Index of the last element of the longest increasing subsequence + # Compute lengths of LIS for all elements for i in range(1, n): for j in range(i): if array[i] > array[j] and dp[i] < dp[j] + 1: @@ -56,14 +67,11 @@ def longest_increasing_subsequence(array: list[int]) -> list[int]: # Reconstructing the longest increasing subsequence lis = [] - i = max_index - while i >= 0: - lis.append(array[i]) - i = prev[i] - if i == -1: - break - - return lis[::-1] + while max_index != -1: + lis.append(array[max_index]) + max_index = prev[max_index] + + return lis[::-1] # The LIS is constructed in reverse order, so reverse it # Longest Common Subsequence (LCS) From 6571286c9306e2ccba18c1f993a9b0e041733b20 Mon Sep 17 00:00:00 2001 From: Satyam Kumar Date: Mon, 7 Oct 2024 23:55:47 +0530 Subject: [PATCH 06/16] Update subsequence_algorithms.py --- dynamic_programming/subsequence_algorithms.py | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/dynamic_programming/subsequence_algorithms.py b/dynamic_programming/subsequence_algorithms.py index 018d4b62577d..c632f34d9456 100644 --- a/dynamic_programming/subsequence_algorithms.py +++ b/dynamic_programming/subsequence_algorithms.py @@ -75,23 +75,37 @@ def longest_increasing_subsequence(array: list[int]) -> list[int]: # Longest Common Subsequence (LCS) -def longest_common_subsequence(x: str, y: str) -> tuple[int, str]: +def longest_common_subsequence(first_sequence: str, second_sequence: str): """ - Finds the longest common subsequence between two strings and its length. + Finds the longest common subsequence between two sequences (strings). + Also returns the subsequence found. - Examples: + Parameters + ---------- + first_sequence: str + The first sequence (or string). + + second_sequence: str + The second sequence (or string). + + Returns + ------- + tuple + - Length of the longest subsequence (int). + - The longest common subsequence found (str). + + Examples + -------- >>> longest_common_subsequence("programming", "gaming") (6, 'gaming') >>> longest_common_subsequence("physics", "smartphone") (2, 'ph') >>> longest_common_subsequence("computer", "food") (1, 'o') - >>> longest_common_subsequence("", "abc") - (0, '') - >>> longest_common_subsequence("abc", "") + >>> longest_common_subsequence("abc", "def") (0, '') - >>> longest_common_subsequence("abcdef", "ace") - (3, 'ace') + >>> longest_common_subsequence("abc", "abc") + (3, 'abc') """ m, n = len(x), len(y) dp = [[0] * (n + 1) for _ in range(m + 1)] From 5f47908e78987b6fa3673fb584aa74c38656bae4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:26:09 +0000 Subject: [PATCH 07/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- dynamic_programming/subsequence_algorithms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dynamic_programming/subsequence_algorithms.py b/dynamic_programming/subsequence_algorithms.py index c632f34d9456..0494d7370a2d 100644 --- a/dynamic_programming/subsequence_algorithms.py +++ b/dynamic_programming/subsequence_algorithms.py @@ -84,7 +84,7 @@ def longest_common_subsequence(first_sequence: str, second_sequence: str): ---------- first_sequence: str The first sequence (or string). - + second_sequence: str The second sequence (or string). From ed509f84e34fe1354a157ee5a75002d8768bcb5f Mon Sep 17 00:00:00 2001 From: Satyam Kumar Date: Tue, 8 Oct 2024 00:00:31 +0530 Subject: [PATCH 08/16] Update subsequence_algorithms.py --- dynamic_programming/subsequence_algorithms.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dynamic_programming/subsequence_algorithms.py b/dynamic_programming/subsequence_algorithms.py index 0494d7370a2d..b03b3a471745 100644 --- a/dynamic_programming/subsequence_algorithms.py +++ b/dynamic_programming/subsequence_algorithms.py @@ -84,7 +84,7 @@ def longest_common_subsequence(first_sequence: str, second_sequence: str): ---------- first_sequence: str The first sequence (or string). - + second_sequence: str The second sequence (or string). @@ -107,12 +107,12 @@ def longest_common_subsequence(first_sequence: str, second_sequence: str): >>> longest_common_subsequence("abc", "abc") (3, 'abc') """ - m, n = len(x), len(y) + m, n = len(first_sequence), len(second_sequence) dp = [[0] * (n + 1) for _ in range(m + 1)] for i in range(1, m + 1): for j in range(1, n + 1): - if x[i - 1] == y[j - 1]: + if first_sequence[i - 1] == second_sequence[j - 1]: dp[i][j] = dp[i - 1][j - 1] + 1 else: dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) @@ -121,8 +121,8 @@ def longest_common_subsequence(first_sequence: str, second_sequence: str): i, j = m, n lcs = [] while i > 0 and j > 0: - if x[i - 1] == y[j - 1]: - lcs.append(x[i - 1]) + if first_sequence[i - 1] == second_sequence[j - 1]: + lcs.append(first_sequence[i - 1]) i -= 1 j -= 1 elif dp[i - 1][j] > dp[i][j - 1]: @@ -133,6 +133,7 @@ def longest_common_subsequence(first_sequence: str, second_sequence: str): return dp[m][n], "".join(reversed(lcs)) + if __name__ == "__main__": import doctest From 4b9949c6a45b7eae824ff7e0de5acc6f000b478d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:30:53 +0000 Subject: [PATCH 09/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- dynamic_programming/subsequence_algorithms.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dynamic_programming/subsequence_algorithms.py b/dynamic_programming/subsequence_algorithms.py index b03b3a471745..8cfd2f6070f5 100644 --- a/dynamic_programming/subsequence_algorithms.py +++ b/dynamic_programming/subsequence_algorithms.py @@ -84,7 +84,7 @@ def longest_common_subsequence(first_sequence: str, second_sequence: str): ---------- first_sequence: str The first sequence (or string). - + second_sequence: str The second sequence (or string). @@ -133,7 +133,6 @@ def longest_common_subsequence(first_sequence: str, second_sequence: str): return dp[m][n], "".join(reversed(lcs)) - if __name__ == "__main__": import doctest From dd69918af2e4ddd2dc56da5b6023368bb0ab25e0 Mon Sep 17 00:00:00 2001 From: Satyam Kumar Date: Tue, 8 Oct 2024 00:02:36 +0530 Subject: [PATCH 10/16] Update subsequence_algorithms.py --- dynamic_programming/subsequence_algorithms.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dynamic_programming/subsequence_algorithms.py b/dynamic_programming/subsequence_algorithms.py index 8cfd2f6070f5..9c07f724e11f 100644 --- a/dynamic_programming/subsequence_algorithms.py +++ b/dynamic_programming/subsequence_algorithms.py @@ -75,7 +75,8 @@ def longest_increasing_subsequence(array: list[int]) -> list[int]: # Longest Common Subsequence (LCS) -def longest_common_subsequence(first_sequence: str, second_sequence: str): +def longest_common_subsequence(first_sequence: str, second_sequence: str) -> tuple[int, str]: + """ Finds the longest common subsequence between two sequences (strings). Also returns the subsequence found. From cf0b0b35600a9c8cf5c9a27209d9fc15143e4c4d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:32:58 +0000 Subject: [PATCH 11/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- dynamic_programming/subsequence_algorithms.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dynamic_programming/subsequence_algorithms.py b/dynamic_programming/subsequence_algorithms.py index 9c07f724e11f..dd51cd1c30aa 100644 --- a/dynamic_programming/subsequence_algorithms.py +++ b/dynamic_programming/subsequence_algorithms.py @@ -75,8 +75,9 @@ def longest_increasing_subsequence(array: list[int]) -> list[int]: # Longest Common Subsequence (LCS) -def longest_common_subsequence(first_sequence: str, second_sequence: str) -> tuple[int, str]: - +def longest_common_subsequence( + first_sequence: str, second_sequence: str +) -> tuple[int, str]: """ Finds the longest common subsequence between two sequences (strings). Also returns the subsequence found. From 9998a4c9a3af50d5f92f12aef633d40c37032c7c Mon Sep 17 00:00:00 2001 From: Satyam Kumar Date: Tue, 8 Oct 2024 00:05:02 +0530 Subject: [PATCH 12/16] Update subsequence_algorithms.py --- dynamic_programming/subsequence_algorithms.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dynamic_programming/subsequence_algorithms.py b/dynamic_programming/subsequence_algorithms.py index dd51cd1c30aa..6b4807c7ce60 100644 --- a/dynamic_programming/subsequence_algorithms.py +++ b/dynamic_programming/subsequence_algorithms.py @@ -75,9 +75,7 @@ def longest_increasing_subsequence(array: list[int]) -> list[int]: # Longest Common Subsequence (LCS) -def longest_common_subsequence( - first_sequence: str, second_sequence: str -) -> tuple[int, str]: +def longest_common_subsequence(first_sequence: str, second_sequence: str) -> tuple[int, str]: """ Finds the longest common subsequence between two sequences (strings). Also returns the subsequence found. @@ -86,7 +84,7 @@ def longest_common_subsequence( ---------- first_sequence: str The first sequence (or string). - + second_sequence: str The second sequence (or string). @@ -135,6 +133,7 @@ def longest_common_subsequence( return dp[m][n], "".join(reversed(lcs)) + if __name__ == "__main__": import doctest From d01865117d978a927a526fb98757aaf1b167e3df Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:35:24 +0000 Subject: [PATCH 13/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- dynamic_programming/subsequence_algorithms.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dynamic_programming/subsequence_algorithms.py b/dynamic_programming/subsequence_algorithms.py index 6b4807c7ce60..dd51cd1c30aa 100644 --- a/dynamic_programming/subsequence_algorithms.py +++ b/dynamic_programming/subsequence_algorithms.py @@ -75,7 +75,9 @@ def longest_increasing_subsequence(array: list[int]) -> list[int]: # Longest Common Subsequence (LCS) -def longest_common_subsequence(first_sequence: str, second_sequence: str) -> tuple[int, str]: +def longest_common_subsequence( + first_sequence: str, second_sequence: str +) -> tuple[int, str]: """ Finds the longest common subsequence between two sequences (strings). Also returns the subsequence found. @@ -84,7 +86,7 @@ def longest_common_subsequence(first_sequence: str, second_sequence: str) -> tup ---------- first_sequence: str The first sequence (or string). - + second_sequence: str The second sequence (or string). @@ -133,7 +135,6 @@ def longest_common_subsequence(first_sequence: str, second_sequence: str) -> tup return dp[m][n], "".join(reversed(lcs)) - if __name__ == "__main__": import doctest From ac7def6596f55410d4d4c967b9442ef0f02368ea Mon Sep 17 00:00:00 2001 From: Satyam Kumar Date: Tue, 8 Oct 2024 00:09:43 +0530 Subject: [PATCH 14/16] Update subsequence_algorithms.py --- dynamic_programming/subsequence_algorithms.py | 153 +++++++++--------- 1 file changed, 77 insertions(+), 76 deletions(-) diff --git a/dynamic_programming/subsequence_algorithms.py b/dynamic_programming/subsequence_algorithms.py index dd51cd1c30aa..375a0b331047 100644 --- a/dynamic_programming/subsequence_algorithms.py +++ b/dynamic_programming/subsequence_algorithms.py @@ -18,121 +18,122 @@ # Longest Increasing Subsequence (LIS) -def longest_increasing_subsequence(array: list[int]) -> list[int]: +def longest_subsequence(array: list[int]) -> list[int]: # This function is recursive """ - Finds the longest increasing subsequence in the given array using dynamic programming. - - Parameters: - ---------- - array: list[int] - The input array of integers. - - Returns: - ------- - list[int] - The longest increasing subsequence (LIS) as a list. - - Examples: - -------- - >>> longest_increasing_subsequence([10, 22, 9, 33, 21, 50, 41, 60, 80]) + Some examples + >>> longest_subsequence([10, 22, 9, 33, 21, 50, 41, 60, 80]) [10, 22, 33, 41, 60, 80] - >>> longest_increasing_subsequence([4, 8, 7, 5, 1, 12, 2, 3, 9]) + >>> longest_subsequence([4, 8, 7, 5, 1, 12, 2, 3, 9]) [1, 2, 3, 9] - >>> longest_increasing_subsequence([9, 8, 7, 6, 5, 7]) - [5, 7] - >>> longest_increasing_subsequence([1, 1, 1]) - [1] - >>> longest_increasing_subsequence([]) + >>> longest_subsequence([9, 8, 7, 6, 5, 7]) + [8] + >>> longest_subsequence([1, 1, 1]) + [1, 1, 1] + >>> longest_subsequence([]) [] """ - if not array: - return [] - - n = len(array) - dp = [1] * n # dp[i] stores the length of the LIS ending at index i - prev = [-1] * n # prev[i] stores the index of the previous element in the LIS - - max_length = 1 # Length of the longest increasing subsequence found - max_index = 0 # Index of the last element of the longest increasing subsequence - - # Compute lengths of LIS for all elements - for i in range(1, n): - for j in range(i): - if array[i] > array[j] and dp[i] < dp[j] + 1: - dp[i] = dp[j] + 1 - prev[i] = j - if dp[i] > max_length: - max_length = dp[i] - max_index = i - - # Reconstructing the longest increasing subsequence - lis = [] - while max_index != -1: - lis.append(array[max_index]) - max_index = prev[max_index] - - return lis[::-1] # The LIS is constructed in reverse order, so reverse it + array_length = len(array) + # If the array contains only one element, we return it (it's the stop condition of + # recursion) + if array_length <= 1: + return array + # Else + pivot = array[0] + is_found = False + i = 1 + longest_subseq: list[int] = [] + while not is_found and i < array_length: + if array[i] < pivot: + is_found = True + temp_array = [element for element in array[i:] if element >= array[i]] + temp_array = longest_subsequence(temp_array) + if len(temp_array) > len(longest_subseq): + longest_subseq = temp_array + else: + i += 1 + temp_array = [element for element in array[1:] if element >= pivot] + temp_array = [pivot, *longest_subsequence(temp_array)] + if len(temp_array) > len(longest_subseq): + return temp_array + else: + return longest_subseq # Longest Common Subsequence (LCS) -def longest_common_subsequence( - first_sequence: str, second_sequence: str -) -> tuple[int, str]: +def longest_common_subsequence(x: str, y: str): """ - Finds the longest common subsequence between two sequences (strings). - Also returns the subsequence found. + Finds the longest common subsequence between two strings. Also returns the + The subsequence found Parameters ---------- - first_sequence: str - The first sequence (or string). - second_sequence: str - The second sequence (or string). + x: str, one of the strings + y: str, the other string Returns ------- - tuple - - Length of the longest subsequence (int). - - The longest common subsequence found (str). + L[m][n]: int, the length of the longest subsequence. Also equal to len(seq) + Seq: str, the subsequence found - Examples - -------- >>> longest_common_subsequence("programming", "gaming") (6, 'gaming') >>> longest_common_subsequence("physics", "smartphone") (2, 'ph') >>> longest_common_subsequence("computer", "food") (1, 'o') - >>> longest_common_subsequence("abc", "def") + >>> longest_common_subsequence("", "abc") # One string is empty + (0, '') + >>> longest_common_subsequence("abc", "") # Other string is empty + (0, '') + >>> longest_common_subsequence("", "") # Both strings are empty (0, '') - >>> longest_common_subsequence("abc", "abc") + >>> longest_common_subsequence("abc", "def") # No common subsequence + (0, '') + >>> longest_common_subsequence("abc", "abc") # Identical strings (3, 'abc') + >>> longest_common_subsequence("a", "a") # Single character match + (1, 'a') + >>> longest_common_subsequence("a", "b") # Single character no match + (0, '') + >>> longest_common_subsequence("abcdef", "ace") # Interleaved subsequence + (3, 'ace') + >>> longest_common_subsequence("ABCD", "ACBD") # No repeated characters + (3, 'ABD') """ - m, n = len(first_sequence), len(second_sequence) + # find the length of strings + + assert x is not None + assert y is not None + + m = len(x) + n = len(y) + + # declaring the array for storing the dp values dp = [[0] * (n + 1) for _ in range(m + 1)] for i in range(1, m + 1): for j in range(1, n + 1): - if first_sequence[i - 1] == second_sequence[j - 1]: - dp[i][j] = dp[i - 1][j - 1] + 1 - else: - dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + match = 1 if x[i - 1] == y[j - 1] else 0 - # Reconstructing the longest common subsequence + dp[i][j] = max(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1] + match) + + seq = "" i, j = m, n - lcs = [] while i > 0 and j > 0: - if first_sequence[i - 1] == second_sequence[j - 1]: - lcs.append(first_sequence[i - 1]) + match = 1 if x[i - 1] == y[j - 1] else 0 + + if dp[i][j] == dp[i - 1][j - 1] + match: + if match == 1: + seq = x[i - 1] + seq i -= 1 j -= 1 - elif dp[i - 1][j] > dp[i][j - 1]: + elif dp[i][j] == dp[i - 1][j]: i -= 1 else: j -= 1 - return dp[m][n], "".join(reversed(lcs)) + return dp[m][n], seq if __name__ == "__main__": From 06f26f44a9a6a044635679709f4c4de186b62617 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:40:04 +0000 Subject: [PATCH 15/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- dynamic_programming/subsequence_algorithms.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dynamic_programming/subsequence_algorithms.py b/dynamic_programming/subsequence_algorithms.py index 375a0b331047..d9041b9546a9 100644 --- a/dynamic_programming/subsequence_algorithms.py +++ b/dynamic_programming/subsequence_algorithms.py @@ -59,6 +59,7 @@ def longest_subsequence(array: list[int]) -> list[int]: # This function is recu else: return longest_subseq + # Longest Common Subsequence (LCS) def longest_common_subsequence(x: str, y: str): """ From 6961be7437776659cbc4fa92a5dea5e87329181d Mon Sep 17 00:00:00 2001 From: Satyam Kumar Date: Tue, 8 Oct 2024 00:11:11 +0530 Subject: [PATCH 16/16] Update subsequence_algorithms.py --- dynamic_programming/subsequence_algorithms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dynamic_programming/subsequence_algorithms.py b/dynamic_programming/subsequence_algorithms.py index d9041b9546a9..f7f224539393 100644 --- a/dynamic_programming/subsequence_algorithms.py +++ b/dynamic_programming/subsequence_algorithms.py @@ -144,7 +144,7 @@ def longest_common_subsequence(x: str, y: str): # Example usage for LIS arr = [10, 22, 9, 33, 21, 50, 41, 60, 80] - lis = longest_increasing_subsequence(arr) + lis = longest_subsequence(arr) print(f"Longest Increasing Subsequence: {lis}") # Example usage for LCS