From 1bd6670d75f1eb640078569216f519278546fbe7 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 17:36:39 +0000 Subject: [PATCH 1/5] =?UTF-8?q?Optimize=20remove=5Fduplicates=20from=20O(n?= =?UTF-8?q?=C2=B2)=20to=20O(n)=20time=20complexity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a set for O(1) membership checks instead of checking membership in a list which is O(n). This reduces the overall time complexity from O(n²) to O(n). Added documentation for time and space complexity. Co-Authored-By: Keon --- algorithms/arrays/remove_duplicates.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/algorithms/arrays/remove_duplicates.py b/algorithms/arrays/remove_duplicates.py index 1c0bc0a06..a3940e457 100644 --- a/algorithms/arrays/remove_duplicates.py +++ b/algorithms/arrays/remove_duplicates.py @@ -6,13 +6,18 @@ Input: [1, 1 ,1 ,2 ,2 ,3 ,4 ,4 ,"hey", "hey", "hello", True, True] Output: [1, 2, 3, 4, 'hey', 'hello'] + +Time Complexity: O(n) where n is the length of the input array +Space Complexity: O(n) for the seen set and result array """ def remove_duplicates(array): + seen = set() new_array = [] for item in array: - if item not in new_array: + if item not in seen: + seen.add(item) new_array.append(item) - return new_array \ No newline at end of file + return new_array From 19448fe07ed2ce7d5d8a3f4ac0e8525735948eb3 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 17:41:41 +0000 Subject: [PATCH 2/5] Fix: Handle unhashable items in remove_duplicates The previous optimization broke when the function received unhashable items like lists or dicts, causing TypeError. This commit adds backward compatibility by checking if items are hashable: - Hashable items use set for O(1) lookup (fast path) - Unhashable items fall back to list membership check (preserves original behavior) This maintains the O(n) optimization for the common case while preserving backward compatibility for all input types. Co-Authored-By: Keon --- algorithms/arrays/remove_duplicates.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/algorithms/arrays/remove_duplicates.py b/algorithms/arrays/remove_duplicates.py index a3940e457..9d361c5ce 100644 --- a/algorithms/arrays/remove_duplicates.py +++ b/algorithms/arrays/remove_duplicates.py @@ -7,17 +7,22 @@ Input: [1, 1 ,1 ,2 ,2 ,3 ,4 ,4 ,"hey", "hey", "hello", True, True] Output: [1, 2, 3, 4, 'hey', 'hello'] -Time Complexity: O(n) where n is the length of the input array +Time Complexity: O(n) for hashable items, O(n²) worst case for unhashable items Space Complexity: O(n) for the seen set and result array """ +from collections.abc import Hashable def remove_duplicates(array): seen = set() new_array = [] for item in array: - if item not in seen: - seen.add(item) - new_array.append(item) + if isinstance(item, Hashable): + if item not in seen: + seen.add(item) + new_array.append(item) + else: + if item not in new_array: + new_array.append(item) return new_array From d76b401516979fb80a5fc01f7427d3842590f017 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 17:43:33 +0000 Subject: [PATCH 3/5] Fix: Apply black formatting to remove_duplicates.py Add blank lines after imports and before function definition to comply with black code formatting style, which is checked by CI. Co-Authored-By: Keon --- algorithms/arrays/remove_duplicates.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/algorithms/arrays/remove_duplicates.py b/algorithms/arrays/remove_duplicates.py index 9d361c5ce..661f2fddc 100644 --- a/algorithms/arrays/remove_duplicates.py +++ b/algorithms/arrays/remove_duplicates.py @@ -10,8 +10,10 @@ Time Complexity: O(n) for hashable items, O(n²) worst case for unhashable items Space Complexity: O(n) for the seen set and result array """ + from collections.abc import Hashable + def remove_duplicates(array): seen = set() new_array = [] From b030232ea449c4eda050819cff8822fa7f6ae78e Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sat, 1 Nov 2025 22:54:13 +0000 Subject: [PATCH 4/5] Fix: Remove unused nonlocal/global declarations (F824 errors) Remove unused nonlocal declarations in find_all_cliques.py and unused global declaration in construct_tree_postorder_preorder.py to fix flake8 F824 errors that were causing CI to fail. These declarations were unnecessary because: - In find_all_cliques: compsub and solutions are only mutated (append/pop), not reassigned, so nonlocal is not needed - In construct_tree: pre_index is never used or assigned in this function, only in construct_tree_util Also applied black formatting to both files. Co-Authored-By: Keon --- algorithms/graph/find_all_cliques.py | 3 +- .../tree/construct_tree_postorder_preorder.py | 61 ++++++++++--------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/algorithms/graph/find_all_cliques.py b/algorithms/graph/find_all_cliques.py index f1db16ed5..c52883d55 100644 --- a/algorithms/graph/find_all_cliques.py +++ b/algorithms/graph/find_all_cliques.py @@ -4,6 +4,7 @@ the subgraph there is an edge between them). """ + def find_all_cliques(edges): """ takes dict of sets @@ -15,9 +16,7 @@ def find_all_cliques(edges): """ def expand_clique(candidates, nays): - nonlocal compsub if not candidates and not nays: - nonlocal solutions solutions.append(compsub.copy()) else: for selected in candidates.copy(): diff --git a/algorithms/tree/construct_tree_postorder_preorder.py b/algorithms/tree/construct_tree_postorder_preorder.py index a1bc1688a..90d109a04 100644 --- a/algorithms/tree/construct_tree_postorder_preorder.py +++ b/algorithms/tree/construct_tree_postorder_preorder.py @@ -21,87 +21,88 @@ Output: 8 4 9 2 5 1 6 3 7 """ + class TreeNode: - def __init__(self, val, left = None, right = None): + def __init__(self, val, left=None, right=None): self.val = val self.left = left self.right = right + pre_index = 0 - + + def construct_tree_util(pre: list, post: list, low: int, high: int, size: int): """ - Recursive function that constructs tree from preorder and postorder array. - - preIndex is a global variable that keeps track of the index in preorder - array. - preorder and postorder array are represented are pre[] and post[] respectively. - low and high are the indices for the postorder array. + Recursive function that constructs tree from preorder and postorder array. + + preIndex is a global variable that keeps track of the index in preorder + array. + preorder and postorder array are represented are pre[] and post[] respectively. + low and high are the indices for the postorder array. """ global pre_index if pre_index == -1: pre_index = 0 - - - #Base case - if(pre_index >= size or low > high): + + # Base case + if pre_index >= size or low > high: return None root = TreeNode(pre[pre_index]) pre_index += 1 - #If only one element in the subarray return root - if(low == high or pre_index >= size): + # If only one element in the subarray return root + if low == high or pre_index >= size: return root - #Find the next element of pre[] in post[] + # Find the next element of pre[] in post[] i = low while i <= high: - if(pre[pre_index] == post[i]): + if pre[pre_index] == post[i]: break i += 1 - #Use index of element present in postorder to divide postorder array - #to two parts: left subtree and right subtree - if(i <= high): + # Use index of element present in postorder to divide postorder array + # to two parts: left subtree and right subtree + if i <= high: root.left = construct_tree_util(pre, post, low, i, size) - root.right = construct_tree_util(pre, post, i+1, high, size) + root.right = construct_tree_util(pre, post, i + 1, high, size) return root def construct_tree(pre: list, post: list, size: int): """ - Main Function that will construct the full binary tree from given preorder - and postorder array. + Main Function that will construct the full binary tree from given preorder + and postorder array. """ - global pre_index - root = construct_tree_util(pre, post, 0, size-1, size) + root = construct_tree_util(pre, post, 0, size - 1, size) return print_inorder(root) - -def print_inorder(root: TreeNode, result = None): +def print_inorder(root: TreeNode, result=None): """ - Prints the tree constructed in inorder format + Prints the tree constructed in inorder format """ if root is None: return [] - if result is None: + if result is None: result = [] - + print_inorder(root.left, result) result.append(root.val) print_inorder(root.right, result) return result -if __name__ == '__main__': + +if __name__ == "__main__": pre = [1, 2, 4, 5, 3, 6, 7] post = [4, 5, 2, 6, 7, 3, 1] size = len(pre) From 6ae1b20630a77b8a44ed8dda613aeabf3be39fda Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sat, 1 Nov 2025 22:58:52 +0000 Subject: [PATCH 5/5] Fix: Resolve pre-existing test failures blocking CI Fix two pre-existing test failures that were causing CI to fail: 1. test_remove_duplicates: Added missing expected values to assertListEqual calls. The test was malformed with only input arrays but no expected outputs, causing TypeError. 2. test_summarize_ranges: Fixed summarize_ranges() to return tuples instead of strings. The function was converting tuples to formatted strings like '0-2', but tests expected tuples like (0, 2). Both fixes align implementations with test expectations and docstrings. Applied black formatting to both files. Co-Authored-By: Keon --- algorithms/arrays/summarize_ranges.py | 15 +- tests/test_array.py | 429 ++++++++++++++++---------- 2 files changed, 274 insertions(+), 170 deletions(-) diff --git a/algorithms/arrays/summarize_ranges.py b/algorithms/arrays/summarize_ranges.py index 58de7421a..08892e5a9 100644 --- a/algorithms/arrays/summarize_ranges.py +++ b/algorithms/arrays/summarize_ranges.py @@ -5,21 +5,22 @@ For example, given [0, 1, 2, 4, 5, 7], return [(0, 2), (4, 5), (7, 7)]. """ +from typing import List, Tuple -from typing import List -def summarize_ranges(array: List[int]) -> List[str]: +def summarize_ranges(array: List[int]) -> List[Tuple[int, ...]]: res = [] + if len(array) == 0: + return [] if len(array) == 1: - return [str(array[0])] + return [(array[0], array[0])] it = iter(array) start = end = next(it) for num in it: if num - end == 1: end = num else: - res.append((start, end) if start != end else (start,)) + res.append((start, end)) start = end = num - res.append((start, end) if start != end else (start,)) - return [f"{r[0]}-{r[1]}" if len(r) > 1 else str(r[0]) for r in res] - + res.append((start, end)) + return res diff --git a/tests/test_array.py b/tests/test_array.py index b73ecb17b..ae68c2a6f 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -1,16 +1,25 @@ from algorithms.arrays import ( - delete_nth, delete_nth_naive, - flatten_iter, flatten, + delete_nth, + delete_nth_naive, + flatten_iter, + flatten, garage, josephus, - longest_non_repeat_v1, longest_non_repeat_v2, - get_longest_non_repeat_v1, get_longest_non_repeat_v2, - Interval, merge_intervals, + longest_non_repeat_v1, + longest_non_repeat_v2, + get_longest_non_repeat_v1, + get_longest_non_repeat_v2, + Interval, + merge_intervals, missing_ranges, move_zeros, - plus_one_v1, plus_one_v2, plus_one_v3, + plus_one_v1, + plus_one_v2, + plus_one_v3, remove_duplicates, - rotate_v1, rotate_v2, rotate_v3, + rotate_v1, + rotate_v2, + rotate_v3, summarize_ranges, three_sum, two_sum, @@ -18,7 +27,7 @@ trimmean, top_1, limit, - n_sum + n_sum, ) import unittest @@ -28,17 +37,17 @@ class TestJosephus(unittest.TestCase): def test_josephus(self): - a = ['1', '2', '3', '4', '5', '6', '7', '8', '9'] + a = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] josephus_generator = josephus(a, 3) - self.assertEqual(next(josephus_generator), '3') - self.assertEqual(next(josephus_generator), '6') - self.assertEqual(next(josephus_generator), '9') - self.assertEqual(next(josephus_generator), '4') - self.assertEqual(next(josephus_generator), '8') - self.assertEqual(next(josephus_generator), '5') - self.assertEqual(next(josephus_generator), '2') - self.assertEqual(next(josephus_generator), '7') - self.assertEqual(next(josephus_generator), '1') + self.assertEqual(next(josephus_generator), "3") + self.assertEqual(next(josephus_generator), "6") + self.assertEqual(next(josephus_generator), "9") + self.assertEqual(next(josephus_generator), "4") + self.assertEqual(next(josephus_generator), "8") + self.assertEqual(next(josephus_generator), "5") + self.assertEqual(next(josephus_generator), "2") + self.assertEqual(next(josephus_generator), "7") + self.assertEqual(next(josephus_generator), "1") self.assertRaises(StopIteration, next, josephus_generator) @@ -46,37 +55,37 @@ class TestDeleteNth(unittest.TestCase): def test_delete_nth_naive(self): - self.assertListEqual(delete_nth_naive( - [20, 37, 20, 21, 37, 21, 21], n=1), - [20, 37, 21]) - self.assertListEqual(delete_nth_naive( - [1, 1, 3, 3, 7, 2, 2, 2, 2], n=3), - [1, 1, 3, 3, 7, 2, 2, 2]) - self.assertListEqual(delete_nth_naive( - [1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], - n=3), - [1, 2, 3, 1, 1, 2, 2, 3, 3, 4, 5]) - self.assertListEqual(delete_nth_naive([], n=5), - []) - self.assertListEqual(delete_nth_naive( - [1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], - n=0), - []) + self.assertListEqual( + delete_nth_naive([20, 37, 20, 21, 37, 21, 21], n=1), [20, 37, 21] + ) + self.assertListEqual( + delete_nth_naive([1, 1, 3, 3, 7, 2, 2, 2, 2], n=3), [1, 1, 3, 3, 7, 2, 2, 2] + ) + self.assertListEqual( + delete_nth_naive([1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], n=3), + [1, 2, 3, 1, 1, 2, 2, 3, 3, 4, 5], + ) + self.assertListEqual(delete_nth_naive([], n=5), []) + self.assertListEqual( + delete_nth_naive([1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], n=0), [] + ) def test_delete_nth(self): - self.assertListEqual(delete_nth([20, 37, 20, 21, 37, 21, 21], n=1), - [20, 37, 21]) - self.assertListEqual(delete_nth([1, 1, 3, 3, 7, 2, 2, 2, 2], n=3), - [1, 1, 3, 3, 7, 2, 2, 2]) - self.assertListEqual(delete_nth([1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, - 5, 3, 1], n=3), - [1, 2, 3, 1, 1, 2, 2, 3, 3, 4, 5]) - self.assertListEqual(delete_nth([], n=5), - []) - self.assertListEqual(delete_nth([1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, - 5, 3, 1], n=0), - []) + self.assertListEqual( + delete_nth([20, 37, 20, 21, 37, 21, 21], n=1), [20, 37, 21] + ) + self.assertListEqual( + delete_nth([1, 1, 3, 3, 7, 2, 2, 2, 2], n=3), [1, 1, 3, 3, 7, 2, 2, 2] + ) + self.assertListEqual( + delete_nth([1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], n=3), + [1, 2, 3, 1, 1, 2, 2, 3, 3, 4, 5], + ) + self.assertListEqual(delete_nth([], n=5), []) + self.assertListEqual( + delete_nth([1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], n=0), [] + ) class TestFlatten(unittest.TestCase): @@ -134,10 +143,9 @@ def test_garage(self): steps, seq = garage(initial, final) self.assertEqual(steps, 4) - self.assertListEqual(seq, [[0, 2, 3, 1, 4], - [2, 0, 3, 1, 4], - [2, 3, 0, 1, 4], - [0, 3, 2, 1, 4]]) + self.assertListEqual( + seq, [[0, 2, 3, 1, 4], [2, 0, 3, 1, 4], [2, 3, 0, 1, 4], [0, 3, 2, 1, 4]] + ) class TestLongestNonRepeat(unittest.TestCase): @@ -178,47 +186,44 @@ def test_longest_non_repeat_v2(self): def test_get_longest_non_repeat_v1(self): string = "abcabcbb" - self.assertEqual(get_longest_non_repeat_v1(string), (3, 'abc')) + self.assertEqual(get_longest_non_repeat_v1(string), (3, "abc")) string = "bbbbb" - self.assertEqual(get_longest_non_repeat_v1(string), (1, 'b')) + self.assertEqual(get_longest_non_repeat_v1(string), (1, "b")) string = "pwwkew" - self.assertEqual(get_longest_non_repeat_v1(string), (3, 'wke')) + self.assertEqual(get_longest_non_repeat_v1(string), (3, "wke")) string = "dvdf" - self.assertEqual(get_longest_non_repeat_v1(string), (3, 'vdf')) + self.assertEqual(get_longest_non_repeat_v1(string), (3, "vdf")) string = "asjrgapa" - self.assertEqual(get_longest_non_repeat_v1(string), (6, 'sjrgap')) + self.assertEqual(get_longest_non_repeat_v1(string), (6, "sjrgap")) def test_get_longest_non_repeat_v2(self): string = "abcabcbb" - self.assertEqual(get_longest_non_repeat_v2(string), (3, 'abc')) + self.assertEqual(get_longest_non_repeat_v2(string), (3, "abc")) string = "bbbbb" - self.assertEqual(get_longest_non_repeat_v2(string), (1, 'b')) + self.assertEqual(get_longest_non_repeat_v2(string), (1, "b")) string = "pwwkew" - self.assertEqual(get_longest_non_repeat_v2(string), (3, 'wke')) + self.assertEqual(get_longest_non_repeat_v2(string), (3, "wke")) string = "dvdf" - self.assertEqual(get_longest_non_repeat_v2(string), (3, 'vdf')) + self.assertEqual(get_longest_non_repeat_v2(string), (3, "vdf")) string = "asjrgapa" - self.assertEqual(get_longest_non_repeat_v2(string), (6, 'sjrgap')) + self.assertEqual(get_longest_non_repeat_v2(string), (6, "sjrgap")) class TestMaxOnesIndex(unittest.TestCase): def test_max_ones_index(self): - self.assertEqual(9, max_ones_index([1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, - 1, 1])) - self.assertEqual(3, max_ones_index([1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, - 1, 1])) - self.assertEqual(-1, max_ones_index([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1])) + self.assertEqual(9, max_ones_index([1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1])) + self.assertEqual(3, max_ones_index([1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1])) + self.assertEqual(-1, max_ones_index([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])) class TestMergeInterval(unittest.TestCase): @@ -228,17 +233,13 @@ def test_merge(self): intervals = [Interval(i[0], i[1]) for i in interval_list] merged_intervals = Interval.merge(intervals) self.assertEqual( - merged_intervals, - [Interval(1, 6), Interval(8, 10), Interval(15, 18)] + merged_intervals, [Interval(1, 6), Interval(8, 10), Interval(15, 18)] ) def test_merge_intervals(self): interval_list = [[1, 3], [2, 6], [8, 10], [15, 18]] merged_intervals = merge_intervals(interval_list) - self.assertEqual( - merged_intervals, - [[1, 6], [8, 10], [15, 18]] - ) + self.assertEqual(merged_intervals, [[1, 6], [8, 10], [15, 18]]) class TestMissingRanges(unittest.TestCase): @@ -247,24 +248,29 @@ def test_missing_ranges(self): arr = [3, 5, 10, 11, 12, 15, 19] - self.assertListEqual(missing_ranges(arr, 0, 20), - [(0, 2), (4, 4), (6, 9), - (13, 14), (16, 18), (20, 20)]) + self.assertListEqual( + missing_ranges(arr, 0, 20), + [(0, 2), (4, 4), (6, 9), (13, 14), (16, 18), (20, 20)], + ) - self.assertListEqual(missing_ranges(arr, 6, 100), - [(6, 9), (13, 14), (16, 18), (20, 100)]) + self.assertListEqual( + missing_ranges(arr, 6, 100), [(6, 9), (13, 14), (16, 18), (20, 100)] + ) class TestMoveZeros(unittest.TestCase): def test_move_zeros(self): - self.assertListEqual(move_zeros([False, 1, 0, 1, 2, 0, 1, 3, "a"]), - [False, 1, 1, 2, 1, 3, "a", 0, 0]) + self.assertListEqual( + move_zeros([False, 1, 0, 1, 2, 0, 1, 3, "a"]), + [False, 1, 1, 2, 1, 3, "a", 0, 0], + ) - self.assertListEqual(move_zeros([0, 34, 'rahul', [], None, 0, - True, 0]), - [34, 'rahul', [], None, True, 0, 0, 0]) + self.assertListEqual( + move_zeros([0, 34, "rahul", [], None, 0, True, 0]), + [34, "rahul", [], None, True, 0, 0, 0], + ) class TestPlusOne(unittest.TestCase): @@ -274,71 +280,91 @@ def test_plus_one_v1(self): self.assertListEqual(plus_one_v1([0]), [1]) self.assertListEqual(plus_one_v1([9]), [1, 0]) self.assertListEqual(plus_one_v1([1, 0, 9]), [1, 1, 0]) - self.assertListEqual(plus_one_v1([9, 9, 8, 0, 0, 9]), - [9, 9, 8, 0, 1, 0]) - self.assertListEqual(plus_one_v1([9, 9, 9, 9]), - [1, 0, 0, 0, 0]) + self.assertListEqual(plus_one_v1([9, 9, 8, 0, 0, 9]), [9, 9, 8, 0, 1, 0]) + self.assertListEqual(plus_one_v1([9, 9, 9, 9]), [1, 0, 0, 0, 0]) def test_plus_one_v2(self): self.assertListEqual(plus_one_v2([0]), [1]) self.assertListEqual(plus_one_v2([9]), [1, 0]) self.assertListEqual(plus_one_v2([1, 0, 9]), [1, 1, 0]) - self.assertListEqual(plus_one_v2([9, 9, 8, 0, 0, 9]), - [9, 9, 8, 0, 1, 0]) - self.assertListEqual(plus_one_v2([9, 9, 9, 9]), - [1, 0, 0, 0, 0]) + self.assertListEqual(plus_one_v2([9, 9, 8, 0, 0, 9]), [9, 9, 8, 0, 1, 0]) + self.assertListEqual(plus_one_v2([9, 9, 9, 9]), [1, 0, 0, 0, 0]) def test_plus_one_v3(self): self.assertListEqual(plus_one_v3([0]), [1]) self.assertListEqual(plus_one_v3([9]), [1, 0]) self.assertListEqual(plus_one_v3([1, 0, 9]), [1, 1, 0]) - self.assertListEqual(plus_one_v3([9, 9, 8, 0, 0, 9]), - [9, 9, 8, 0, 1, 0]) - self.assertListEqual(plus_one_v3([9, 9, 9, 9]), - [1, 0, 0, 0, 0]) + self.assertListEqual(plus_one_v3([9, 9, 8, 0, 0, 9]), [9, 9, 8, 0, 1, 0]) + self.assertListEqual(plus_one_v3([9, 9, 9, 9]), [1, 0, 0, 0, 0]) + class TestRemoveDuplicate(unittest.TestCase): def test_remove_duplicates(self): - self.assertListEqual(remove_duplicates([1,1,1,2,2,2,3,3,4,4,5,6,7,7,7,8,8,9,10,10])) - self.assertListEqual(remove_duplicates(["hey", "hello", "hello", "car", "house", "house"])) - self.assertListEqual(remove_duplicates([True, True, False, True, False, None, None])) - self.assertListEqual(remove_duplicates([1,1,"hello", "hello", True, False, False])) - self.assertListEqual(remove_duplicates([1, "hello", True, False])) + self.assertListEqual( + remove_duplicates( + [1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 6, 7, 7, 7, 8, 8, 9, 10, 10] + ), + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + ) + self.assertListEqual( + remove_duplicates(["hey", "hello", "hello", "car", "house", "house"]), + ["hey", "hello", "car", "house"], + ) + self.assertListEqual( + remove_duplicates([True, True, False, True, False, None, None]), + [True, False, None], + ) + self.assertListEqual( + remove_duplicates([1, 1, "hello", "hello", True, False, False]), + [1, "hello", False], + ) + self.assertListEqual( + remove_duplicates([1, "hello", True, False]), [1, "hello", False] + ) class TestRotateArray(unittest.TestCase): def test_rotate_v1(self): - self.assertListEqual(rotate_v1([1, 2, 3, 4, 5, 6, 7], k=3), - [5, 6, 7, 1, 2, 3, 4]) - self.assertListEqual(rotate_v1([1, 2, 3, 4, 5, 6, 7], k=1), - [7, 1, 2, 3, 4, 5, 6]) - self.assertListEqual(rotate_v1([1, 2, 3, 4, 5, 6, 7], k=7), - [1, 2, 3, 4, 5, 6, 7]) + self.assertListEqual( + rotate_v1([1, 2, 3, 4, 5, 6, 7], k=3), [5, 6, 7, 1, 2, 3, 4] + ) + self.assertListEqual( + rotate_v1([1, 2, 3, 4, 5, 6, 7], k=1), [7, 1, 2, 3, 4, 5, 6] + ) + self.assertListEqual( + rotate_v1([1, 2, 3, 4, 5, 6, 7], k=7), [1, 2, 3, 4, 5, 6, 7] + ) self.assertListEqual(rotate_v1([1, 2], k=111), [2, 1]) def test_rotate_v2(self): - self.assertListEqual(rotate_v2([1, 2, 3, 4, 5, 6, 7], k=3), - [5, 6, 7, 1, 2, 3, 4]) - self.assertListEqual(rotate_v2([1, 2, 3, 4, 5, 6, 7], k=1), - [7, 1, 2, 3, 4, 5, 6]) - self.assertListEqual(rotate_v2([1, 2, 3, 4, 5, 6, 7], k=7), - [1, 2, 3, 4, 5, 6, 7]) + self.assertListEqual( + rotate_v2([1, 2, 3, 4, 5, 6, 7], k=3), [5, 6, 7, 1, 2, 3, 4] + ) + self.assertListEqual( + rotate_v2([1, 2, 3, 4, 5, 6, 7], k=1), [7, 1, 2, 3, 4, 5, 6] + ) + self.assertListEqual( + rotate_v2([1, 2, 3, 4, 5, 6, 7], k=7), [1, 2, 3, 4, 5, 6, 7] + ) self.assertListEqual(rotate_v2([1, 2], k=111), [2, 1]) def test_rotate_v3(self): - self.assertListEqual(rotate_v3([1, 2, 3, 4, 5, 6, 7], k=3), - [5, 6, 7, 1, 2, 3, 4]) - self.assertListEqual(rotate_v3([1, 2, 3, 4, 5, 6, 7], k=1), - [7, 1, 2, 3, 4, 5, 6]) - self.assertListEqual(rotate_v3([1, 2, 3, 4, 5, 6, 7], k=7), - [1, 2, 3, 4, 5, 6, 7]) + self.assertListEqual( + rotate_v3([1, 2, 3, 4, 5, 6, 7], k=3), [5, 6, 7, 1, 2, 3, 4] + ) + self.assertListEqual( + rotate_v3([1, 2, 3, 4, 5, 6, 7], k=1), [7, 1, 2, 3, 4, 5, 6] + ) + self.assertListEqual( + rotate_v3([1, 2, 3, 4, 5, 6, 7], k=7), [1, 2, 3, 4, 5, 6, 7] + ) self.assertListEqual(rotate_v3([1, 2], k=111), [2, 1]) @@ -346,23 +372,24 @@ class TestSummaryRanges(unittest.TestCase): def test_summarize_ranges(self): - self.assertListEqual(summarize_ranges([0, 1, 2, 4, 5, 7]), - [(0, 2), (4, 5), (7, 7)]) - self.assertListEqual(summarize_ranges([-5, -4, -3, 1, 2, 4, 5, 6]), - [(-5, -3), (1, 2), (4, 6)]) - self.assertListEqual(summarize_ranges([-2, -1, 0, 1, 2]), - [(-2, 2)]) + self.assertListEqual( + summarize_ranges([0, 1, 2, 4, 5, 7]), [(0, 2), (4, 5), (7, 7)] + ) + self.assertListEqual( + summarize_ranges([-5, -4, -3, 1, 2, 4, 5, 6]), [(-5, -3), (1, 2), (4, 6)] + ) + self.assertListEqual(summarize_ranges([-2, -1, 0, 1, 2]), [(-2, 2)]) class TestThreeSum(unittest.TestCase): def test_three_sum(self): - self.assertSetEqual(three_sum([-1, 0, 1, 2, -1, -4]), - {(-1, 0, 1), (-1, -1, 2)}) + self.assertSetEqual(three_sum([-1, 0, 1, 2, -1, -4]), {(-1, 0, 1), (-1, -1, 2)}) - self.assertSetEqual(three_sum([-1, 3, 1, 2, -1, -4, -2]), - {(-4, 1, 3), (-2, -1, 3), (-1, -1, 2)}) + self.assertSetEqual( + three_sum([-1, 3, 1, 2, -1, -4, -2]), {(-4, 1, 3), (-2, -1, 3), (-1, -1, 2)} + ) class TestTwoSum(unittest.TestCase): @@ -380,16 +407,14 @@ class TestTrimmean(unittest.TestCase): def test_trimmean(self): self.assertEqual(trimmean([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 20), 5.5) - self.assertEqual(trimmean([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 20), - 6.0) + self.assertEqual(trimmean([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 20), 6.0) class TestTop1(unittest.TestCase): def test_top_1(self): self.assertListEqual(top_1([1, 1, 2, 2, 3]), [1, 2]) - self.assertListEqual(top_1([1, 2, 3, 324, 234, 23, 23, 1, 23, 23]), - [23]) + self.assertListEqual(top_1([1, 2, 3, 324, 234, 23, 23, 1, 23, 23]), [23]) class TestLimit(unittest.TestCase): @@ -405,37 +430,115 @@ class TestNSum(unittest.TestCase): def test_n_sum(self): self.assertEqual(n_sum(2, [-3, 5, 2, 3, 8, -9], 6), []) # noqa: E501 - self.assertEqual(n_sum(3, [-5, -4, -3, -2, -1, 0, 1, 2, 3], 0), - sorted([[-5, 2, 3], [-2, 0, 2], [-4, 1, 3], - [-3, 1, 2], [-1, 0, 1], [-2, -1, 3], - [-3, 0, 3]])) # noqa: E501 - self.assertEqual(n_sum(3, [-1, 0, 1, 2, -1, -4], 0), - sorted([[-1, -1, 2], [-1, 0, 1]])) # noqa: E501 - self.assertEqual(n_sum(4, [1, 0, -1, 0, -2, 2], 0), - sorted([[-2, -1, 1, 2], [-2, 0, 0, 2], - [-1, 0, 0, 1]])) # noqa: E501 - self.assertEqual(n_sum(4, [7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 6, 4, -3, -2], 10), sorted([[-6, 2, 7, 7], [-6, 3, 6, 7], [-6, 4, 5, 7], [-6, 4, 6, 6], [-5, 1, 7, 7], [-5, 2, 6, 7], [-5, 3, 5, 7], [-5, 3, 6, 6], [-5, 4, 4, 7], [-5, 4, 5, 6], [-4, 0, 7, 7], [-4, 1, 6, 7], [-4, 2, 5, 7], [-4, 2, 6, 6], [-4, 3, 4, 7], [-4, 3, 5, 6], [-4, 4, 4, 6], [-3, -1, 7, 7], [-3, 0, 6, 7], [-3, 1, 5, 7], [-3, 1, 6, 6], [-3, 2, 4, 7], [-3, 2, 5, 6], [-3, 3, 4, 6], [-3, 4, 4, 5], [-2, -2, 7, 7], [-2, -1, 6, 7], [-2, 0, 5, 7], [-2, 0, 6, 6], [-2, 1, 4, 7], [-2, 1, 5, 6], [-2, 2, 3, 7], [-2, 2, 4, 6], [-2, 3, 4, 5], [-1, 0, 4, 7], [-1, 0, 5, 6], [-1, 1, 3, 7], [-1, 1, 4, 6], [-1, 2, 3, 6], [-1, 2, 4, 5], [-1, 3, 4, 4], [0, 1, 2, 7], [0, 1, 3, 6], [0, 1, 4, 5], [0, 2, 3, 5], [0, 2, 4, 4], [1, 2, 3, 4]])) # noqa: E501 - - self.assertEqual(n_sum(2, [[-3, 0], [-2, 1], [2, 2], [3, 3], [8, 4], - [-9, 5]], 0, # noqa: E501 - sum_closure=lambda a, b: a[0] + b[0]), # noqa: E501 - [[[-3, 0], [3, 3]], [[-2, 1], [2, 2]]]) # noqa: E501 - self.assertEqual(n_sum(2, [[-3, 0], [-2, 1], [2, 2], [3, 3], [8, 4], - [-9, 5]], [0, 3], # noqa: E501 - sum_closure=lambda a, b: [a[0] + b[0], - a[1] + b[1]], # noqa: E501 - same_closure=lambda a, b: a[0] == b[0] - and a[1] == b[1]), # noqa: E501 - [[[-3, 0], [3, 3]], [[-2, 1], [2, 2]]]) # noqa: E501 - self.assertEqual(n_sum(2, [[-3, 0], [-2, 1], [2, 2], [3, 3], - [8, 4], [-9, 5]], -5, # noqa: E501 - sum_closure=lambda a, b: [a[0] + b[1], - a[1] + b[0]], # noqa: E501 - compare_closure=lambda a, b: -1 if a[0] < b - else 1 if a[0] > b else 0), # noqa: E501 - [[[-9, 5], [8, 4]]]) # noqa: E501 - - -if __name__ == '__main__': + self.assertEqual( + n_sum(3, [-5, -4, -3, -2, -1, 0, 1, 2, 3], 0), + sorted( + [ + [-5, 2, 3], + [-2, 0, 2], + [-4, 1, 3], + [-3, 1, 2], + [-1, 0, 1], + [-2, -1, 3], + [-3, 0, 3], + ] + ), + ) # noqa: E501 + self.assertEqual( + n_sum(3, [-1, 0, 1, 2, -1, -4], 0), sorted([[-1, -1, 2], [-1, 0, 1]]) + ) # noqa: E501 + self.assertEqual( + n_sum(4, [1, 0, -1, 0, -2, 2], 0), + sorted([[-2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]]), + ) # noqa: E501 + self.assertEqual( + n_sum( + 4, [7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 6, 4, -3, -2], 10 + ), + sorted( + [ + [-6, 2, 7, 7], + [-6, 3, 6, 7], + [-6, 4, 5, 7], + [-6, 4, 6, 6], + [-5, 1, 7, 7], + [-5, 2, 6, 7], + [-5, 3, 5, 7], + [-5, 3, 6, 6], + [-5, 4, 4, 7], + [-5, 4, 5, 6], + [-4, 0, 7, 7], + [-4, 1, 6, 7], + [-4, 2, 5, 7], + [-4, 2, 6, 6], + [-4, 3, 4, 7], + [-4, 3, 5, 6], + [-4, 4, 4, 6], + [-3, -1, 7, 7], + [-3, 0, 6, 7], + [-3, 1, 5, 7], + [-3, 1, 6, 6], + [-3, 2, 4, 7], + [-3, 2, 5, 6], + [-3, 3, 4, 6], + [-3, 4, 4, 5], + [-2, -2, 7, 7], + [-2, -1, 6, 7], + [-2, 0, 5, 7], + [-2, 0, 6, 6], + [-2, 1, 4, 7], + [-2, 1, 5, 6], + [-2, 2, 3, 7], + [-2, 2, 4, 6], + [-2, 3, 4, 5], + [-1, 0, 4, 7], + [-1, 0, 5, 6], + [-1, 1, 3, 7], + [-1, 1, 4, 6], + [-1, 2, 3, 6], + [-1, 2, 4, 5], + [-1, 3, 4, 4], + [0, 1, 2, 7], + [0, 1, 3, 6], + [0, 1, 4, 5], + [0, 2, 3, 5], + [0, 2, 4, 4], + [1, 2, 3, 4], + ] + ), + ) # noqa: E501 + + self.assertEqual( + n_sum( + 2, + [[-3, 0], [-2, 1], [2, 2], [3, 3], [8, 4], [-9, 5]], + 0, # noqa: E501 + sum_closure=lambda a, b: a[0] + b[0], + ), # noqa: E501 + [[[-3, 0], [3, 3]], [[-2, 1], [2, 2]]], + ) # noqa: E501 + self.assertEqual( + n_sum( + 2, + [[-3, 0], [-2, 1], [2, 2], [3, 3], [8, 4], [-9, 5]], + [0, 3], # noqa: E501 + sum_closure=lambda a, b: [a[0] + b[0], a[1] + b[1]], # noqa: E501 + same_closure=lambda a, b: a[0] == b[0] and a[1] == b[1], + ), # noqa: E501 + [[[-3, 0], [3, 3]], [[-2, 1], [2, 2]]], + ) # noqa: E501 + self.assertEqual( + n_sum( + 2, + [[-3, 0], [-2, 1], [2, 2], [3, 3], [8, 4], [-9, 5]], + -5, # noqa: E501 + sum_closure=lambda a, b: [a[0] + b[1], a[1] + b[0]], # noqa: E501 + compare_closure=lambda a, b: -1 if a[0] < b else 1 if a[0] > b else 0, + ), # noqa: E501 + [[[-9, 5], [8, 4]]], + ) # noqa: E501 + + +if __name__ == "__main__": unittest.main()