From 66eb36d27721676000f9a656a2fa3987963de176 Mon Sep 17 00:00:00 2001 From: Canderton74 <108482522+Canderton74@users.noreply.github.com> Date: Fri, 27 Jun 2025 01:29:58 -0400 Subject: [PATCH 1/6] Fixed polynomial division (#2130) --- algorithms/maths/polynomial.py | 79 ++++++++++++++++++++++++++-------- tests/test_polynomial.py | 70 ++++++++++++++++++++---------- 2 files changed, 109 insertions(+), 40 deletions(-) diff --git a/algorithms/maths/polynomial.py b/algorithms/maths/polynomial.py index 07a0c3b8a..81faf2b7e 100644 --- a/algorithms/maths/polynomial.py +++ b/algorithms/maths/polynomial.py @@ -438,10 +438,7 @@ def __floordiv__(self, other: Union[int, float, Fraction, Monomial]): # def __truediv__(self, other: Union[int, float, Fraction, Monomial, Polynomial]) -> Polynomial: def __truediv__(self, other: Union[int, float, Fraction, Monomial]): """ - For Polynomials, only division by a monomial - is defined. - - TODO: Implement polynomial / polynomial. + For Polynomial division, no remainder is provided. Must use poly_long_division() to capture remainder """ if isinstance(other, int) or isinstance(other, float) or isinstance(other, Fraction): return self.__truediv__( Monomial({}, other) ) @@ -449,17 +446,11 @@ def __truediv__(self, other: Union[int, float, Fraction, Monomial]): poly_temp = reduce(lambda acc, val: acc + val, map(lambda x: x / other, [z for z in self.all_monomials()]), Polynomial([Monomial({}, 0)])) return poly_temp elif isinstance(other, Polynomial): - if Monomial({}, 0) in other.all_monomials(): - if len(other.all_monomials()) == 2: - temp_set = {x for x in other.all_monomials() if x != Monomial({}, 0)} - only = temp_set.pop() - return self.__truediv__(only) - elif len(other.all_monomials()) == 1: - temp_set = {x for x in other.all_monomials()} - only = temp_set.pop() - return self.__truediv__(only) - - raise ValueError('Can only divide a polynomial by an int, float, Fraction, or a Monomial.') + # Call long division + quotient, remainder = self.poly_long_division(other) + return quotient # Return just the quotient, remainder is ignored here + + raise ValueError('Can only divide a polynomial by an int, float, Fraction, Monomial, or Polynomial.') return @@ -526,7 +517,59 @@ def subs(self, substitutions: Union[int, float, Fraction, Dict[int, Union[int, f def __str__(self) -> str: """ - Get a string representation of - the polynomial. + Get a properly formatted string representation of the polynomial. + """ + sorted_monos = sorted(self.all_monomials(), key=lambda m: sorted(m.variables.items(), reverse=True), + reverse=True) + return ' + '.join(str(m) for m in sorted_monos if m.coeff != Fraction(0, 1)) + + def poly_long_division(self, other: 'Polynomial') -> tuple['Polynomial', 'Polynomial']: """ - return ' + '.join(str(m) for m in self.all_monomials() if m.coeff != Fraction(0, 1)) + Perform polynomial long division + Returns (quotient, remainder) + """ + if not isinstance(other, Polynomial): + raise ValueError("Can only divide by another Polynomial.") + + if len(other.all_monomials()) == 0: + raise ValueError("Cannot divide by zero polynomial.") + + quotient = Polynomial([]) + remainder = self.clone() + + divisor_monos = sorted(other.all_monomials(), key=lambda m: sorted(m.variables.items(), reverse=True), + reverse=True) + divisor_lead = divisor_monos[0] + + while remainder.all_monomials() and max(remainder.variables(), default=-1) >= max(other.variables(), + default=-1): + remainder_monos = sorted(remainder.all_monomials(), key=lambda m: sorted(m.variables.items(), reverse=True), + reverse=True) + remainder_lead = remainder_monos[0] + + if not all(remainder_lead.variables.get(var, 0) >= divisor_lead.variables.get(var, 0) for var in + divisor_lead.variables): + break + + lead_quotient = remainder_lead / divisor_lead + quotient = quotient + Polynomial([lead_quotient]) # Convert Monomial to Polynomial + + remainder = remainder - ( + Polynomial([lead_quotient]) * other) # Convert Monomial to Polynomial before multiplication + + return quotient, remainder + +dividend = Polynomial([ + Monomial({1: 3}, 4), # 4(a_1)^3 + Monomial({1: 2}, 3), # 3(a_1)^2 + Monomial({1: 1}, -2), # -2(a_1) + Monomial({}, 5) # +5 +]) + +divisor = Polynomial([ + Monomial({1: 1}, 2), # 2(a_1) + Monomial({}, -1) # -1 +]) + +quotient = dividend / divisor +print("Quotient:", quotient) diff --git a/tests/test_polynomial.py b/tests/test_polynomial.py index 4ba2ba6b7..ab5674017 100644 --- a/tests/test_polynomial.py +++ b/tests/test_polynomial.py @@ -105,27 +105,6 @@ def test_polynomial_multiplication(self): ])) return - def test_polynomial_division(self): - - # Should raise a ValueError if the divisor is not a monomial - # or a polynomial with only one term. - self.assertRaises(ValueError, lambda x, y: x / y, self.p5, self.p3) - self.assertRaises(ValueError, lambda x, y: x / y, self.p6, self.p4) - - self.assertEqual(self.p3 / self.p2, Polynomial([ - Monomial({}, 1), - Monomial({1: 1, 2: -1}, 0.75) - ])) - self.assertEqual(self.p7 / self.m1, Polynomial([ - Monomial({1: -1, 2: -3}, 2), - Monomial({1: 0, 2: -4}, 1.5) - ])) - self.assertEqual(self.p7 / self.m1, Polynomial([ - Monomial({1: -1, 2: -3}, 2), - Monomial({2: -4}, 1.5) - ])) - return - def test_polynomial_variables(self): # The zero polynomial has no variables. @@ -172,4 +151,51 @@ def test_polynomial_clone(self): self.assertEqual(self.p5.clone(), Polynomial([ Monomial({1: -1, 3: 2}, 1) ])) - return \ No newline at end of file + return + + def test_polynomial_long_division(self): + """ + Test polynomial long division + """ + + # Dividend: 4a_1^3 + 3a_1^2 - 2a_1 + 5 + dividend = Polynomial([ + Monomial({1: 3}, 4), # 4(a_1)^3 + Monomial({1: 2}, 3), # 3(a_1)^2 + Monomial({1: 1}, -2), # -2(a_1) + Monomial({}, 5) # +5 + ]) + + # Divisor: 2a_1 - 1 + divisor = Polynomial([ + Monomial({1: 1}, 2), # 2(a_1) + Monomial({}, -1) # -1 + ]) + + # Expected Quotient: 2a_1^2 + (5/2)a_1 + 1/4 + expected_quotient = Polynomial([ + Monomial({1: 2}, 2), # 2(a_1)^2 + Monomial({1: 1}, Fraction(5, 2)), # (5/2)(a_1) + Monomial({}, Fraction(1, 4)) # +1/4 + ]) + + # Expected Remainder: 21/4 + expected_remainder = Polynomial([ + Monomial({}, Fraction(21, 4)) # 21/4 + ]) + + quotient_long_div, remainder_long_div = dividend.poly_long_division(divisor) + + quotient_truediv = dividend / divisor # Calls __truediv__, which returns only the quotient + + # Check if quotient from poly_long_division matches expected + self.assertEqual(quotient_long_div, expected_quotient) + + # Check if remainder from poly_long_division matches expected + self.assertEqual(remainder_long_div, expected_remainder) + + # Check if quotient from __truediv__ matches quotient from poly_long_division + self.assertEqual(quotient_truediv, quotient_long_div) + + return + From 0b04e60364fe02dc04c5232f274286bcbbee1049 Mon Sep 17 00:00:00 2001 From: Chadndrabhan Patel <88890660+cpatel321@users.noreply.github.com> Date: Fri, 27 Jun 2025 11:00:17 +0530 Subject: [PATCH 2/6] Update test_array.py (missing comma at line 12) (#2047) --- tests/test_array.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_array.py b/tests/test_array.py index f1ad11693..b73ecb17b 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -9,7 +9,7 @@ missing_ranges, move_zeros, plus_one_v1, plus_one_v2, plus_one_v3, - remove_duplicates + remove_duplicates, rotate_v1, rotate_v2, rotate_v3, summarize_ranges, three_sum, From 486fa37782e956c28449b109ba6864ceb78a3972 Mon Sep 17 00:00:00 2001 From: shirleymaza <166472849+shirleymaza@users.noreply.github.com> Date: Fri, 27 Jun 2025 01:30:32 -0400 Subject: [PATCH 3/6] Added Bead Sort Algorithm #920 (#2100) --- algorithms/sort/bead_sort.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 algorithms/sort/bead_sort.py diff --git a/algorithms/sort/bead_sort.py b/algorithms/sort/bead_sort.py new file mode 100644 index 000000000..0d949fa82 --- /dev/null +++ b/algorithms/sort/bead_sort.py @@ -0,0 +1,26 @@ +""" +Bead Sort (also known as Gravity Sort) is a natural sorting algorithm that simulates how beads would settle under gravity on an abacus. It is most useful for sorting positive integers, especially when the range of numbers isn't excessively large. However, it is not a comparison-based sort and is generally impractical for large inputs due to its reliance on physical modeling. +Time Complexity +- Best Case: O(n) if the numbers are already sorted +- Average Case: O(n^2) because each bead needs to be placed and then fall under gravity +- Worst Case: O(n^2) since each bead must "fall" individually +""" + +def bead_sort(arr): + if any(num < 0 for num in arr): + raise ValueError("Bead sort only works with non-negative integers.") + + max_num = max(arr) if arr else 0 + grid = [[0] * len(arr) for _ in range(max_num)] + + # Drop beads (place beads in columns) + for col, num in enumerate(arr): + for row in range(num): + grid[row][col] = 1 + + # Let the beads "fall" (count beads in each row) + for row in grid: + sum_beads = sum(row) + for col in range(len(arr)): + row[col] = 1 if col < sum_beads else 0 + From 67287d2fa924be67db8465cc17144abdcc21643a Mon Sep 17 00:00:00 2001 From: PiyushGoel0612 <121474233+PiyushGoel0612@users.noreply.github.com> Date: Fri, 10 Oct 2025 02:36:11 +0530 Subject: [PATCH 4/6] Added the validate bst function (#2696) * Added the validate bst function * Added the validate bst function --------- Co-authored-by: Piyush Goel --- algorithms/tree/bst/validate_bst.py | 90 +++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 algorithms/tree/bst/validate_bst.py diff --git a/algorithms/tree/bst/validate_bst.py b/algorithms/tree/bst/validate_bst.py new file mode 100644 index 000000000..81dfc1952 --- /dev/null +++ b/algorithms/tree/bst/validate_bst.py @@ -0,0 +1,90 @@ +# =============================================================================== +# Validate Binary Search Tree +''' +To check if the given binary tree is a valid binary search tree (BST), we need to ensure that: + 1. The left subtree of a node contains only nodes with keys less than the node's key. + 2. The right subtree of a node contains only nodes with keys greater than the node's key. + 3. Both the left and right subtrees must also be binary search trees. +''' +# =============================================================================== + +# Tree class definition +class TreeNode: + + def __init__(self, value): + + self.val = value + self.left = None + self.right = None + +# Function to validate if a binary tree is a BST +def validate_bst(node): + ''' + Validate if a binary tree is a binary search tree (BST). + Input params : Tree Node to be validated + Returns : Tuple ( + is_bst: bool, + min_value: int | None, + max_value: int | None + ) + ''' + + # Base case: An empty tree is a valid BST + if not node: + return (True, None, None) + + # Validate the left and right subtrees + valid_left, minn_left, maxx_left = validate_bst(node.left) + valid_right, minn_right, maxx_right = validate_bst(node.right) + + # If either subtree is not valid, the whole tree is not a valid BST + if not valid_left or not valid_right: + return ( + False, + minn_left if minn_left else node.val, + maxx_right if maxx_right else node.val + ) + + # Check the current node's value against the max of the left subtree + if maxx_left is not None and maxx_left > node.val: + return ( + False, + minn_left if minn_left else node.val, + maxx_right if maxx_right else node.val + ) + + # Check the current node's value against the min of the right subtree + if minn_right is not None and minn_right < node.val: + return ( + False, + minn_left if minn_left else node.val, + maxx_right if maxx_right else node.val + ) + + # If all checks pass, the tree/subtree is a valid BST + return ( + True, + minn_left if minn_left is not None else node.val, + maxx_right if maxx_right is not None else node.val + ) + +# Example usage +if __name__ == "__main__": + # Constructing a simple binary tree + root = TreeNode(10) + root.left = TreeNode(5) + root.right = TreeNode(15) + root.right.left = TreeNode(12) + root.right.right = TreeNode(20) + + ''' + 10 + / \ + 5 15 + / \ + 12 20 + ''' + + # Validate if the constructed tree is a BST + is_bst, _, _ = validate_bst(root) + print(f"The tree is a valid BST: {is_bst}") \ No newline at end of file From 5b63e90624bebb371949fbe49bbf20aa3c8e14d0 Mon Sep 17 00:00:00 2001 From: Carlo Fraley <148927755+Carlo-Fr@users.noreply.github.com> Date: Thu, 9 Oct 2025 17:07:28 -0400 Subject: [PATCH 5/6] Added Gale-Shapley algorithm with test cases (#2013) --- algorithms/greedy/__init__.py | 1 + algorithms/greedy/gale_shapley.py | 90 +++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 algorithms/greedy/gale_shapley.py diff --git a/algorithms/greedy/__init__.py b/algorithms/greedy/__init__.py index 66184782e..ee28ff0f3 100644 --- a/algorithms/greedy/__init__.py +++ b/algorithms/greedy/__init__.py @@ -1 +1,2 @@ from .max_contiguous_subsequence_sum import * +from .gale_shapley import * \ No newline at end of file diff --git a/algorithms/greedy/gale_shapley.py b/algorithms/greedy/gale_shapley.py new file mode 100644 index 000000000..c86556074 --- /dev/null +++ b/algorithms/greedy/gale_shapley.py @@ -0,0 +1,90 @@ +""" +The Gale-Shapley algorithm is a method to solve the +stable matching/marriage problem. Given N men and women +with ranked preferences of the opposite sex, the men and +women will be matched so that each pair of man and woman +would not prefer someone over their current match. With +no conflicting preferences, the matches are stable. The +algorithm can be extended to issues that involve ranked +matching. + +Example for function: + M denotes man, W denotes woman, and number corresponds to + respective man/woman. Preference lists go from highest to lowest. + + men_preferences = { + "M1": ["W1", "W2", "W3"], + "M2": ["W1", "W3", "W2"], + "M3": ["W3", "W1", "W2"], + } + women_preferences = { + "W1": ["M2", "M1", "M3"], + "W2": ["M1", "M2", "M3"], + "W3": ["M3", "M1", "M2"], + } + + input: print(gale_shapley(men_preferences, women_preferences)) + output: {'M2': 'W1', 'M3': 'W3', 'M1': 'W2'} + Explanation: + Both Man 1 and Man 2 have a top preference of Woman 1, + and since Woman 1 has a top preference of Man 2, Man 2 + and Woman 1 are matched, and Man 1 is added back to available + men. Man 3 and Woman 3 have their top preference as each other, + so the two are matched. Man 1 then proposes to Woman 2, and + Man 1 is the top preference of Woman 2, so the two are matched. + There is no match of Man AND Woman where both would want to + leave, so the current matches are stable. + +""" + +# size denotes the number of men/women +# Function takes in dictionary for men and women preferences in style outlined above +def gale_shapley(men, women): + size = len(men) + # Initialize all men to be available + men_available = list(men.keys()) + # Initialize married to empty + married = {} + # Intialize proposal count for each man to 0 + proposal_counts = {man: 0 for man in men} + while men_available: + # Pop first available man + man = men_available.pop(0) + # Of the popped man, set woman equal to corresponding proposal index + woman = men[man][proposal_counts[man]] + #increment proposal count + proposal_counts[man] += 1 + if woman not in married: + # Set marriage if woman not married + married[woman] = man + else: + # If woman married, currently_married corresponds to currently matched man + currently_married = married[woman] + if women[woman].index(man) < women[woman].index(currently_married): + """ + If the available man is of greater preference to the woman than her + currently married partner, change the marriage to the new available + man and append the previously married man back to men_available + """ + married[woman] = man + men_available.append(currently_married) + else: + # Add man back to men_available and try woman at next index + men_available.append(man) + # Returns pairs of matched men and women in form of Man:Woman + return {man: woman for woman, man in married.items()} + +# Example case +men_preferences = { + "M1": ["W1", "W2", "W3"], + "M2": ["W1", "W3", "W2"], + "M3": ["W3", "W1", "W2"], +} +women_preferences = { + "W1": ["M2", "M1", "M3"], + "W2": ["M1", "M2", "M3"], + "W3": ["M3", "M1", "M2"], +} + +res = gale_shapley(men_preferences, women_preferences) +print(res) \ No newline at end of file From 5991e05d58daf461ed6a9fc05e47afafc851fd2f Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sun, 2 Nov 2025 19:08:44 -0500 Subject: [PATCH 6/6] =?UTF-8?q?Optimize=20remove=5Fduplicates=20from=20O(n?= =?UTF-8?q?=C2=B2)=20to=20O(n)=20time=20complexity=20(#2700)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Optimize remove_duplicates from O(n²) to O(n) time complexity 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 * 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 * 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 * 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 * 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 --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Keon --- algorithms/arrays/remove_duplicates.py | 18 +- algorithms/arrays/summarize_ranges.py | 15 +- algorithms/graph/find_all_cliques.py | 3 +- .../tree/construct_tree_postorder_preorder.py | 61 +-- tests/test_array.py | 429 +++++++++++------- 5 files changed, 321 insertions(+), 205 deletions(-) diff --git a/algorithms/arrays/remove_duplicates.py b/algorithms/arrays/remove_duplicates.py index 1c0bc0a06..661f2fddc 100644 --- a/algorithms/arrays/remove_duplicates.py +++ b/algorithms/arrays/remove_duplicates.py @@ -6,13 +6,25 @@ 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) 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 new_array: - 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 \ No newline at end of file + return new_array 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/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) 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()