From 50fd067dd24360865dc02fdb799077aae5337e6d Mon Sep 17 00:00:00 2001 From: parth Date: Mon, 2 Oct 2023 12:19:39 +0530 Subject: [PATCH 1/6] added algorithm to remove duplicates from a linked list --- .../linked_list/remove_duplicates.py | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 data_structures/linked_list/remove_duplicates.py diff --git a/data_structures/linked_list/remove_duplicates.py b/data_structures/linked_list/remove_duplicates.py new file mode 100644 index 000000000000..da988cb544de --- /dev/null +++ b/data_structures/linked_list/remove_duplicates.py @@ -0,0 +1,102 @@ +from __future__ import annotations + +from dataclasses import dataclass + +@dataclass +class Node: + data: int + next_node: Node | None = None + +def print_linked_list(head: Node | None) -> None: + """ + Print the entire linked list iteratively. + + >>> head = insert_node(None, 0) + >>> head = insert_node(head, 2) + >>> head = insert_node(head, 1) + >>> print_linked_list(head) + 0->2->1 + >>> head = insert_node(head, 4) + >>> head = insert_node(head, 5) + >>> print_linked_list(head) + 0->2->1->4->5 + """ + if head is None: + return + while head.next_node is not None: + print(head.data, end="->") + head = head.next_node + print(head.data) + +def insert_node(head: Node | None, data: int) -> Node: + """ + Insert a new node at the end of a linked list + and return the new head. + + >>> head = insert_node(None, 10) + >>> head = insert_node(head, 9) + >>> head = insert_node(head, 8) + >>> print_linked_list(head) + 10->9->8 + """ + new_node = Node(data) + if head is None: + return new_node + + temp_node = head + while temp_node.next_node: + temp_node = temp_node.next_node + temp_node.next_node = new_node + return head + +def remove_duplicates(head:Node | None): + """ + Remove nodes with duplicate data + + >>> head=insert_node(None,1) + >>> head=insert_node(head,1) + >>> head=insert_node(head,2) + >>> head=insert_node(head,3) + >>> head=insert_node(head,3) + >>> head=insert_node(head,4) + >>> head=insert_node(head,5) + >>> head=insert_node(head,5) + >>> head=insert_node(head,3) + >>> new_head= remove_duplicates(head) + >>> print_linked_list(new_head) + 1->2->3->4->5 + """ + if head is None or head.next_node is None: + return head + + has_occurred=dict() + + new_head=head + last_node=head + has_occurred[head.data]=True + current_node=head.next_node + while current_node is not None: + if current_node.data not in has_occurred.keys(): + last_node.next_node=current_node + last_node=current_node + has_occurred[current_node.data]=True + current_node=current_node.next_node + last_node.next_node=None + return new_head + +if __name__ == "__main__": + import doctest + + doctest.testmod() + + head=insert_node(None,1) + head=insert_node(head,1) + head=insert_node(head,2) + head=insert_node(head,3) + head=insert_node(head,3) + head=insert_node(head,4) + head=insert_node(head,5) + head=insert_node(head,5) + + new_head= remove_duplicates(head) + print_linked_list(new_head) \ No newline at end of file From 638538349cb67d7e910eac33a17c48d94b3c9179 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 06:53:09 +0000 Subject: [PATCH 2/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../linked_list/remove_duplicates.py | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/data_structures/linked_list/remove_duplicates.py b/data_structures/linked_list/remove_duplicates.py index da988cb544de..c7d088f55ae8 100644 --- a/data_structures/linked_list/remove_duplicates.py +++ b/data_structures/linked_list/remove_duplicates.py @@ -2,11 +2,13 @@ from dataclasses import dataclass + @dataclass class Node: data: int next_node: Node | None = None + def print_linked_list(head: Node | None) -> None: """ Print the entire linked list iteratively. @@ -28,6 +30,7 @@ def print_linked_list(head: Node | None) -> None: head = head.next_node print(head.data) + def insert_node(head: Node | None, data: int) -> Node: """ Insert a new node at the end of a linked list @@ -46,10 +49,11 @@ def insert_node(head: Node | None, data: int) -> Node: temp_node = head while temp_node.next_node: temp_node = temp_node.next_node - temp_node.next_node = new_node + temp_node.next_node = new_node return head -def remove_duplicates(head:Node | None): + +def remove_duplicates(head: Node | None): """ Remove nodes with duplicate data @@ -69,34 +73,35 @@ def remove_duplicates(head:Node | None): if head is None or head.next_node is None: return head - has_occurred=dict() + has_occurred = dict() - new_head=head - last_node=head - has_occurred[head.data]=True - current_node=head.next_node + new_head = head + last_node = head + has_occurred[head.data] = True + current_node = head.next_node while current_node is not None: if current_node.data not in has_occurred.keys(): - last_node.next_node=current_node - last_node=current_node - has_occurred[current_node.data]=True - current_node=current_node.next_node - last_node.next_node=None + last_node.next_node = current_node + last_node = current_node + has_occurred[current_node.data] = True + current_node = current_node.next_node + last_node.next_node = None return new_head + if __name__ == "__main__": import doctest doctest.testmod() - head=insert_node(None,1) - head=insert_node(head,1) - head=insert_node(head,2) - head=insert_node(head,3) - head=insert_node(head,3) - head=insert_node(head,4) - head=insert_node(head,5) - head=insert_node(head,5) - - new_head= remove_duplicates(head) - print_linked_list(new_head) \ No newline at end of file + head = insert_node(None, 1) + head = insert_node(head, 1) + head = insert_node(head, 2) + head = insert_node(head, 3) + head = insert_node(head, 3) + head = insert_node(head, 4) + head = insert_node(head, 5) + head = insert_node(head, 5) + + new_head = remove_duplicates(head) + print_linked_list(new_head) From 329035256734352ad2c37c1adfb267379e807db1 Mon Sep 17 00:00:00 2001 From: parth Date: Mon, 2 Oct 2023 12:31:18 +0530 Subject: [PATCH 3/6] update --- data_structures/linked_list/remove_duplicates.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/data_structures/linked_list/remove_duplicates.py b/data_structures/linked_list/remove_duplicates.py index c7d088f55ae8..735480d63ea0 100644 --- a/data_structures/linked_list/remove_duplicates.py +++ b/data_structures/linked_list/remove_duplicates.py @@ -53,7 +53,7 @@ def insert_node(head: Node | None, data: int) -> Node: return head -def remove_duplicates(head: Node | None): +def remove_duplicates(head: Node | None) -> Node | None: """ Remove nodes with duplicate data @@ -65,7 +65,7 @@ def remove_duplicates(head: Node | None): >>> head=insert_node(head,4) >>> head=insert_node(head,5) >>> head=insert_node(head,5) - >>> head=insert_node(head,3) + >>> head=insert_node(head,5) >>> new_head= remove_duplicates(head) >>> print_linked_list(new_head) 1->2->3->4->5 @@ -73,14 +73,14 @@ def remove_duplicates(head: Node | None): if head is None or head.next_node is None: return head - has_occurred = dict() + has_occurred = {} new_head = head last_node = head has_occurred[head.data] = True current_node = head.next_node while current_node is not None: - if current_node.data not in has_occurred.keys(): + if current_node.data not in has_occurred: last_node.next_node = current_node last_node = current_node has_occurred[current_node.data] = True From 6fcc91c9f5986140c7e7855ff1580621e06bae14 Mon Sep 17 00:00:00 2001 From: parth Date: Mon, 2 Oct 2023 12:37:08 +0530 Subject: [PATCH 4/6] updates --- data_structures/linked_list/remove_duplicates.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/data_structures/linked_list/remove_duplicates.py b/data_structures/linked_list/remove_duplicates.py index 735480d63ea0..91c97268a7c5 100644 --- a/data_structures/linked_list/remove_duplicates.py +++ b/data_structures/linked_list/remove_duplicates.py @@ -31,7 +31,7 @@ def print_linked_list(head: Node | None) -> None: print(head.data) -def insert_node(head: Node | None, data: int) -> Node: +def insert_node(head: Node | None, data: int) -> Node | None: """ Insert a new node at the end of a linked list and return the new head. @@ -78,7 +78,9 @@ def remove_duplicates(head: Node | None) -> Node | None: new_head = head last_node = head has_occurred[head.data] = True - current_node = head.next_node + current_node = None + if head.next_node: + current_node = head.next_node while current_node is not None: if current_node.data not in has_occurred: last_node.next_node = current_node From 55a02a1d392abf835fd1df8fceea427dca77a85e Mon Sep 17 00:00:00 2001 From: parth Date: Thu, 5 Oct 2023 00:22:11 +0530 Subject: [PATCH 5/6] added dp algorithm for counting distinct subsequences --- dynamic_programming/distinct_subsequences.py | 46 ++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 dynamic_programming/distinct_subsequences.py diff --git a/dynamic_programming/distinct_subsequences.py b/dynamic_programming/distinct_subsequences.py new file mode 100644 index 000000000000..d30599568e58 --- /dev/null +++ b/dynamic_programming/distinct_subsequences.py @@ -0,0 +1,46 @@ +from future import __annotations__ + +def subsequenceCounting(s1: str, s2: str, n: int, m: int) -> int: + """ + Uses bottom-up dynamic programming/tabulation + to count the number of distinct + subsequences of string s2 in string s1 + + >>> s1 = "babgbag" + >>> s2 = "bag" + >>> subsequenceCounting(s1, s2, len(s1), len(s2)) + """ + # Initialize a DP table to store the count of distinct subsequences + dp = [[0 for i in range(m + 1)] for j in range(n + 1)] + + # Base case: There is exactly one subsequence of an empty string s2 in s1 + for i in range(n + 1): + dp[i][0] = 1 + + # Initialize dp[0][i] to 0 for i > 0 since an empty s1 cannot have a non-empty subsequence of s2 + for i in range(1, m + 1): + dp[0][i] = 0 + + # Fill in the DP table using dynamic programming + for i in range(1, n + 1): + for j in range(1, m + 1): + # If the current characters match, we have two choices: + # 1. Include the current character in both s1 and s2 (dp[i-1][j-1]) + # 2. Skip the current character in s1 (dp[i-1][j]) + if s1[i - 1] == s2[j - 1]: + dp[i][j] = (dp[i - 1][j - 1] + dp[i - 1][j]) + else: + dp[i - 1][j] + + # The final value in dp[n][m] is the count of distinct subsequences + return dp[n][m] + +if __name__ == "__main__": + import doctest + + doctest.testmod() + s1 = "babgbag" + s2 = "bag" + + # Find the number of distinct subsequences of string s2 in string s1 + print("The Count of Distinct Subsequences is", subsequenceCounting(s1, s2, len(s1), len(s2))) From bbb717a2e13dc2c4075412a0a1ee0f16e1974e13 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 4 Oct 2023 18:53:31 +0000 Subject: [PATCH 6/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- dynamic_programming/distinct_subsequences.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/dynamic_programming/distinct_subsequences.py b/dynamic_programming/distinct_subsequences.py index d30599568e58..8e7efaedfc3f 100644 --- a/dynamic_programming/distinct_subsequences.py +++ b/dynamic_programming/distinct_subsequences.py @@ -1,9 +1,10 @@ from future import __annotations__ + def subsequenceCounting(s1: str, s2: str, n: int, m: int) -> int: """ Uses bottom-up dynamic programming/tabulation - to count the number of distinct + to count the number of distinct subsequences of string s2 in string s1 >>> s1 = "babgbag" @@ -28,19 +29,23 @@ def subsequenceCounting(s1: str, s2: str, n: int, m: int) -> int: # 1. Include the current character in both s1 and s2 (dp[i-1][j-1]) # 2. Skip the current character in s1 (dp[i-1][j]) if s1[i - 1] == s2[j - 1]: - dp[i][j] = (dp[i - 1][j - 1] + dp[i - 1][j]) + dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j] else: dp[i - 1][j] # The final value in dp[n][m] is the count of distinct subsequences return dp[n][m] + if __name__ == "__main__": import doctest doctest.testmod() s1 = "babgbag" s2 = "bag" - + # Find the number of distinct subsequences of string s2 in string s1 - print("The Count of Distinct Subsequences is", subsequenceCounting(s1, s2, len(s1), len(s2))) + print( + "The Count of Distinct Subsequences is", + subsequenceCounting(s1, s2, len(s1), len(s2)), + )