From e14e0fb92fa1b10c769090dd64d0a20e5be847d2 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Wed, 7 Jun 2023 21:43:12 +0000 Subject: [PATCH 01/20] updating DIRECTORY.md --- DIRECTORY.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 231b0e2f1d2f..e28f2697136e 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -419,8 +419,9 @@ * [Frequent Pattern Graph Miner](graphs/frequent_pattern_graph_miner.py) * [G Topological Sort](graphs/g_topological_sort.py) * [Gale Shapley Bigraph](graphs/gale_shapley_bigraph.py) + * [Graph Adjacency List](graphs/graph_adjacency_list.py) + * [Graph Adjacency Matrix](graphs/graph_adjacency_matrix.py) * [Graph List](graphs/graph_list.py) - * [Graph Matrix](graphs/graph_matrix.py) * [Graphs Floyd Warshall](graphs/graphs_floyd_warshall.py) * [Greedy Best First](graphs/greedy_best_first.py) * [Greedy Min Vertex Cover](graphs/greedy_min_vertex_cover.py) @@ -479,6 +480,7 @@ * [Lib](linear_algebra/src/lib.py) * [Polynom For Points](linear_algebra/src/polynom_for_points.py) * [Power Iteration](linear_algebra/src/power_iteration.py) + * [Rank Of Matrix](linear_algebra/src/rank_of_matrix.py) * [Rayleigh Quotient](linear_algebra/src/rayleigh_quotient.py) * [Schur Complement](linear_algebra/src/schur_complement.py) * [Test Linear Algebra](linear_algebra/src/test_linear_algebra.py) @@ -651,6 +653,7 @@ * [Sigmoid Linear Unit](maths/sigmoid_linear_unit.py) * [Signum](maths/signum.py) * [Simpson Rule](maths/simpson_rule.py) + * [Simultaneous Linear Equation Solver](maths/simultaneous_linear_equation_solver.py) * [Sin](maths/sin.py) * [Sock Merchant](maths/sock_merchant.py) * [Softmax](maths/softmax.py) From 05e435f05986f756b5b9b909e5de137b15170893 Mon Sep 17 00:00:00 2001 From: CaedenPH Date: Thu, 8 Jun 2023 16:11:01 +0100 Subject: [PATCH 02/20] feat: Count negative numbers in sorted matrix --- ...count_negative_numbers_in_sorted_matrix.py | 183 ++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 matrix/count_negative_numbers_in_sorted_matrix.py diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py new file mode 100644 index 000000000000..c660cc36cb3d --- /dev/null +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -0,0 +1,183 @@ +""" +Given an `m x n` matrix grid which is sorted in non-increasing order +both row-wise and column-wise, return the number of negative numbers in grid. + +> https://leetcode.com/problems/count-negative-numbers-in-a-sorted-matrix +""" + + +def find_negative_index(array: list[int]): + """ + Find the smallest negative index + + >>> find_negative_index([0,0,0,0]) + 4 + >>> find_negative_index([4,3,2,-1]) + 3 + >>> find_negative_index([1,0,-1,-10]) + 2 + >>> find_negative_index([0,0,0,-1]) + 3 + >>> find_negative_index([11,8,7,-3,-5,-9]) + 3 + >>> find_negative_index([-1,-1,-2,-3]) + 0 + >>> find_negative_index([5,1,0]) + 3 + >>> find_negative_index([-5,-5,-5]) + 0 + >>> find_negative_index([0]) + 1 + >>> find_negative_index([]) + 0 + """ + left = 0 + right = len(array) - 1 + + # Edge cases such as no values or + # all numbers are negative + if not array or array[0] < 0: + return 0 + + while right + 1 > left: + mid = (left + right) // 2 + num = array[mid] + + # Num must be negative and the index about num + # must be greater than or equal to 0 + if num < 0 and array[mid - 1] >= 0: + return mid + + if num >= 0: + left = mid + 1 + else: + right = mid - 1 + # No negative numbers so return the last index + # of the array + 1 which is also the length + return len(array) + + +def count_negatives_binary_search(grid: list[list[int]]) -> int: + """ + An O(m logn) solution that uses binary search + in order to find the boundary betweem positive and + negative numbers + + >>> count_negatives_binary_search( + ... [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]]) + 8 + >>> count_negatives_binary_search([[3,2],[1,0]]) + 0 + >>> count_negatives_binary_search([[7,7,6]]) + 0 + >>> count_negatives_binary_search([[7,7,6],[-1,-2,-3]]) + 3 + """ + total = 0 + bound = len(grid[0]) + + for i in range(len(grid)): + bound = find_negative_index(grid[i][:bound]) + total += bound + return (len(grid) * len(grid[0])) - total + + +def count_negatives_brute_force(grid: list[list[int]]) -> int: + """ + This solution is O(n^2) because it iterates through + every column and row. + + >>> count_negatives_brute_force( + ... [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]]) + 8 + >>> count_negatives_brute_force([[3,2],[1,0]]) + 0 + >>> count_negatives_brute_force([[7,7,6]]) + 0 + >>> count_negatives_brute_force([[7,7,6],[-1,-2,-3]]) + 3 + """ + total = 0 + for m in range(len(grid)): + for n in range(len(grid[m])): + if grid[m][n] < 0: + total += 1 + return total + + +def count_negatives_brute_force_with_break(grid: list[list[int]]) -> int: + """ + Similiar to the solution above, however uses break + in order to reduce the number of iterations + + >>> count_negatives_brute_force_with_break( + ... [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]]) + 8 + >>> count_negatives_brute_force_with_break([[3,2],[1,0]]) + 0 + >>> count_negatives_brute_force_with_break([[7,7,6]]) + 0 + >>> count_negatives_brute_force_with_break([[7,7,6],[-1,-2,-3]]) + 3 + """ + total = 0 + length_of_n = len(grid[0]) + for m in range(len(grid)): + for index, n in enumerate(range(length_of_n)): + if grid[m][n] < 0: + total += length_of_n - index + break + return total + + +def generate_large_matrix() -> list[list[int]]: + """ + >>> generate_large_matrix() # doctest: +ELLIPSIS + [[500, ..., -499], [499, ..., -501], ..., [2, ..., -998]] + """ + return [list(range(1000 - i, -1000 - i, -1)) for i in range(1000)] + + +def benchmark() -> None: + """Benchmark our functions next to each other""" + from timeit import timeit + + print("Running benchmarks") + setup = ( + "from __main__ import count_negatives_binary_search, count_negatives_brute_force, " + "count_negatives_brute_force_with_break, generate_large_matrix" + ) + + cnbs = timeit( + "count_negatives_binary_search(generate_large_matrix())", + setup=setup, + number=5000, + ), + + print("count_negatives_binary_search()", cnbs[0], "seconds") + print( + "count_negatives_brute_force_with_break()", + timeit( + "count_negatives_brute_force_with_break(generate_large_matrix())", + setup=setup, + number=5000, + ), + "seconds", + ) # + print( + "count_negatives_brute_force()", + timeit( + "count_negatives_brute_force(generate_large_matrix())", + setup=setup, + number=5000, + ), + "seconds", + ) + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + + benchmark() From 83d877c2b69ef8d691d4acc6d9872007f2e47cea Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Thu, 8 Jun 2023 15:12:24 +0000 Subject: [PATCH 03/20] updating DIRECTORY.md --- DIRECTORY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 6dac4a9a5783..8511c261a3d2 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -679,6 +679,7 @@ ## Matrix * [Binary Search Matrix](matrix/binary_search_matrix.py) * [Count Islands In Matrix](matrix/count_islands_in_matrix.py) + * [Count Negative Numbers In Sorted Matrix](matrix/count_negative_numbers_in_sorted_matrix.py) * [Count Paths](matrix/count_paths.py) * [Cramers Rule 2X2](matrix/cramers_rule_2x2.py) * [Inverse Of Matrix](matrix/inverse_of_matrix.py) @@ -753,6 +754,7 @@ * [Potential Energy](physics/potential_energy.py) * [Rms Speed Of Molecule](physics/rms_speed_of_molecule.py) * [Shear Stress](physics/shear_stress.py) + * [Speed Of Sound](physics/speed_of_sound.py) ## Project Euler * Problem 001 From f0a785cdce908fb588978a561740505740e1f98f Mon Sep 17 00:00:00 2001 From: CaedenPH Date: Thu, 8 Jun 2023 16:26:27 +0100 Subject: [PATCH 04/20] chore: Fix pre-commit --- ...count_negative_numbers_in_sorted_matrix.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py index c660cc36cb3d..de8f151cafff 100644 --- a/matrix/count_negative_numbers_in_sorted_matrix.py +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -60,7 +60,7 @@ def find_negative_index(array: list[int]): def count_negatives_binary_search(grid: list[list[int]]) -> int: """ An O(m logn) solution that uses binary search - in order to find the boundary betweem positive and + in order to find the boundary between positive and negative numbers >>> count_negatives_binary_search( @@ -107,7 +107,7 @@ def count_negatives_brute_force(grid: list[list[int]]) -> int: def count_negatives_brute_force_with_break(grid: list[list[int]]) -> int: """ - Similiar to the solution above, however uses break + Similar to the solution above, however uses break in order to reduce the number of iterations >>> count_negatives_brute_force_with_break( @@ -133,7 +133,7 @@ def count_negatives_brute_force_with_break(grid: list[list[int]]) -> int: def generate_large_matrix() -> list[list[int]]: """ >>> generate_large_matrix() # doctest: +ELLIPSIS - [[500, ..., -499], [499, ..., -501], ..., [2, ..., -998]] + [[1000, ..., -999], [999, ..., -1001], ..., [2, ..., -1998]] """ return [list(range(1000 - i, -1000 - i, -1)) for i in range(1000)] @@ -144,17 +144,19 @@ def benchmark() -> None: print("Running benchmarks") setup = ( - "from __main__ import count_negatives_binary_search, count_negatives_brute_force, " - "count_negatives_brute_force_with_break, generate_large_matrix" + "from __main__ import count_negatives_binary_search,count_negatives_brute_force" + ",count_negatives_brute_force_with_break,generate_large_matrix" ) - cnbs = timeit( + print( + "count_negatives_binary_search()", + timeit( "count_negatives_binary_search(generate_large_matrix())", setup=setup, number=5000, ), - - print("count_negatives_binary_search()", cnbs[0], "seconds") + "seconds", + ) print( "count_negatives_brute_force_with_break()", timeit( @@ -163,7 +165,7 @@ def benchmark() -> None: number=5000, ), "seconds", - ) # + ) print( "count_negatives_brute_force()", timeit( From 8cd5cdcb6161a63136141bfbc1e63a2aa9a2042b Mon Sep 17 00:00:00 2001 From: CaedenPH Date: Thu, 8 Jun 2023 16:31:29 +0100 Subject: [PATCH 05/20] refactor: Combine functions into iteration --- ...count_negative_numbers_in_sorted_matrix.py | 35 ++++--------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py index de8f151cafff..98fee5af8f98 100644 --- a/matrix/count_negative_numbers_in_sorted_matrix.py +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -147,34 +147,13 @@ def benchmark() -> None: "from __main__ import count_negatives_binary_search,count_negatives_brute_force" ",count_negatives_brute_force_with_break,generate_large_matrix" ) - - print( - "count_negatives_binary_search()", - timeit( - "count_negatives_binary_search(generate_large_matrix())", - setup=setup, - number=5000, - ), - "seconds", - ) - print( - "count_negatives_brute_force_with_break()", - timeit( - "count_negatives_brute_force_with_break(generate_large_matrix())", - setup=setup, - number=5000, - ), - "seconds", - ) - print( - "count_negatives_brute_force()", - timeit( - "count_negatives_brute_force(generate_large_matrix())", - setup=setup, - number=5000, - ), - "seconds", - ) + for func in ( + "count_negatives_binary_search", + "count_negatives_brute_force_with_break", + "count_negatives_brute_force", + ): + time = timeit(f"{func}(generate_large_matrix())", setup=setup, number=5000) + print(f"{func}() took {time} seconds") if __name__ == "__main__": From ea5b2d0777ada189399557378cec9f5d654c1999 Mon Sep 17 00:00:00 2001 From: CaedenPH Date: Thu, 8 Jun 2023 16:33:13 +0100 Subject: [PATCH 06/20] style: Reformat reference --- matrix/count_negative_numbers_in_sorted_matrix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py index 98fee5af8f98..dbcdd80d8fed 100644 --- a/matrix/count_negative_numbers_in_sorted_matrix.py +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -2,7 +2,7 @@ Given an `m x n` matrix grid which is sorted in non-increasing order both row-wise and column-wise, return the number of negative numbers in grid. -> https://leetcode.com/problems/count-negative-numbers-in-a-sorted-matrix +Leetcode reference: https://leetcode.com/problems/count-negative-numbers-in-a-sorted-matrix """ From 0e346b266d49f49bec2da40557c5141169ddb4e8 Mon Sep 17 00:00:00 2001 From: CaedenPH Date: Thu, 8 Jun 2023 16:40:36 +0100 Subject: [PATCH 07/20] feat: Add timings of each implementation --- matrix/count_negative_numbers_in_sorted_matrix.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py index dbcdd80d8fed..da6a52e2fe2b 100644 --- a/matrix/count_negative_numbers_in_sorted_matrix.py +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -148,9 +148,9 @@ def benchmark() -> None: ",count_negatives_brute_force_with_break,generate_large_matrix" ) for func in ( - "count_negatives_binary_search", - "count_negatives_brute_force_with_break", - "count_negatives_brute_force", + "count_negatives_binary_search", # 175.51 seconds + "count_negatives_brute_force_with_break", # 271.04 seconds + "count_negatives_brute_force", # 646.65 seconds ): time = timeit(f"{func}(generate_large_matrix())", setup=setup, number=5000) print(f"{func}() took {time} seconds") From b58a34013315ed2060ba9dad4936f17589cc619b Mon Sep 17 00:00:00 2001 From: CaedenPH Date: Thu, 8 Jun 2023 16:43:00 +0100 Subject: [PATCH 08/20] chore: Fix problems with algorithms-keeper bot --- matrix/count_negative_numbers_in_sorted_matrix.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py index da6a52e2fe2b..5cbdceaf5b5a 100644 --- a/matrix/count_negative_numbers_in_sorted_matrix.py +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -6,7 +6,7 @@ """ -def find_negative_index(array: list[int]): +def find_negative_index(array: list[int]) -> int: """ Find the smallest negative index @@ -139,7 +139,10 @@ def generate_large_matrix() -> list[list[int]]: def benchmark() -> None: - """Benchmark our functions next to each other""" + """Benchmark our functions next to each other + + >>> benchmark() + """ from timeit import timeit print("Running benchmarks") From 3b16704538c96552833304f138957a94a6715127 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 8 Jun 2023 15:43:36 +0000 Subject: [PATCH 09/20] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- matrix/count_negative_numbers_in_sorted_matrix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py index 5cbdceaf5b5a..92726db189b3 100644 --- a/matrix/count_negative_numbers_in_sorted_matrix.py +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -140,7 +140,7 @@ def generate_large_matrix() -> list[list[int]]: def benchmark() -> None: """Benchmark our functions next to each other - + >>> benchmark() """ from timeit import timeit From fca6e9d8187e6f55a9919a32f29b19c06be890fe Mon Sep 17 00:00:00 2001 From: CaedenPH Date: Thu, 8 Jun 2023 16:47:34 +0100 Subject: [PATCH 10/20] test: Remove doctest from benchmark function --- matrix/count_negative_numbers_in_sorted_matrix.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py index 92726db189b3..6fafff1456f8 100644 --- a/matrix/count_negative_numbers_in_sorted_matrix.py +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -139,10 +139,7 @@ def generate_large_matrix() -> list[list[int]]: def benchmark() -> None: - """Benchmark our functions next to each other - - >>> benchmark() - """ + """Benchmark our functions next to each other""" from timeit import timeit print("Running benchmarks") From 02cd4f38b0278e9a6eb2dc0ecaa5e08c88f42e4b Mon Sep 17 00:00:00 2001 From: Caeden Perelli-Harris Date: Fri, 9 Jun 2023 15:45:15 +0100 Subject: [PATCH 11/20] Update matrix/count_negative_numbers_in_sorted_matrix.py Co-authored-by: Christian Clauss --- matrix/count_negative_numbers_in_sorted_matrix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py index 6fafff1456f8..a0e928928a3d 100644 --- a/matrix/count_negative_numbers_in_sorted_matrix.py +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -1,5 +1,5 @@ """ -Given an `m x n` matrix grid which is sorted in non-increasing order +Given an `m x n` matrix grid which is sorted in decreasing order both row-wise and column-wise, return the number of negative numbers in grid. Leetcode reference: https://leetcode.com/problems/count-negative-numbers-in-a-sorted-matrix From 63c5147a3f8427c22842425771e1d514dd6fa299 Mon Sep 17 00:00:00 2001 From: Caeden Perelli-Harris Date: Fri, 9 Jun 2023 17:20:53 +0100 Subject: [PATCH 12/20] Update matrix/count_negative_numbers_in_sorted_matrix.py Co-authored-by: Christian Clauss --- matrix/count_negative_numbers_in_sorted_matrix.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py index a0e928928a3d..138f03869652 100644 --- a/matrix/count_negative_numbers_in_sorted_matrix.py +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -1,6 +1,6 @@ """ -Given an `m x n` matrix grid which is sorted in decreasing order -both row-wise and column-wise, return the number of negative numbers in grid. +Given an matrix of numbers in which all rows and all columns are sorted in decreasing +order, return the number of negative numbers in grid. Leetcode reference: https://leetcode.com/problems/count-negative-numbers-in-a-sorted-matrix """ From a55db732f0d9d37eb8ca69a5a6baa0429bb6f4bf Mon Sep 17 00:00:00 2001 From: Caeden Perelli-Harris Date: Sat, 10 Jun 2023 12:40:30 +0100 Subject: [PATCH 13/20] Update matrix/count_negative_numbers_in_sorted_matrix.py Co-authored-by: Christian Clauss --- matrix/count_negative_numbers_in_sorted_matrix.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py index 138f03869652..e42481ac682b 100644 --- a/matrix/count_negative_numbers_in_sorted_matrix.py +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -121,11 +121,10 @@ def count_negatives_brute_force_with_break(grid: list[list[int]]) -> int: 3 """ total = 0 - length_of_n = len(grid[0]) - for m in range(len(grid)): - for index, n in enumerate(range(length_of_n)): - if grid[m][n] < 0: - total += length_of_n - index + for row in grid: + for i, number in enumerate(row): + if number < 0: + total += len(row) - i break return total From 0d8a616a6de601e2522ba78f4f1c6fbcdd9c08f9 Mon Sep 17 00:00:00 2001 From: Caeden Perelli-Harris Date: Sat, 10 Jun 2023 12:40:43 +0100 Subject: [PATCH 14/20] Update matrix/count_negative_numbers_in_sorted_matrix.py Co-authored-by: Christian Clauss --- matrix/count_negative_numbers_in_sorted_matrix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py index e42481ac682b..4d1834bce4b5 100644 --- a/matrix/count_negative_numbers_in_sorted_matrix.py +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -151,7 +151,7 @@ def benchmark() -> None: "count_negatives_brute_force_with_break", # 271.04 seconds "count_negatives_brute_force", # 646.65 seconds ): - time = timeit(f"{func}(generate_large_matrix())", setup=setup, number=5000) + time = timeit(f"{func}(grid=grid)", setup=setup, number=500) print(f"{func}() took {time} seconds") From 9a7719c57960ee486d4f59a1e1576c7b5dff35a0 Mon Sep 17 00:00:00 2001 From: Caeden Perelli-Harris Date: Sat, 10 Jun 2023 12:40:49 +0100 Subject: [PATCH 15/20] Update matrix/count_negative_numbers_in_sorted_matrix.py Co-authored-by: Christian Clauss --- matrix/count_negative_numbers_in_sorted_matrix.py | 1 + 1 file changed, 1 insertion(+) diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py index 4d1834bce4b5..1b36df52cbab 100644 --- a/matrix/count_negative_numbers_in_sorted_matrix.py +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -137,6 +137,7 @@ def generate_large_matrix() -> list[list[int]]: return [list(range(1000 - i, -1000 - i, -1)) for i in range(1000)] +grid = generate_large_matrix() def benchmark() -> None: """Benchmark our functions next to each other""" from timeit import timeit From 7a2f01e8925b4d56593073056843e95b9d2ef931 Mon Sep 17 00:00:00 2001 From: Caeden Perelli-Harris Date: Sat, 10 Jun 2023 12:40:56 +0100 Subject: [PATCH 16/20] Update matrix/count_negative_numbers_in_sorted_matrix.py Co-authored-by: Christian Clauss --- matrix/count_negative_numbers_in_sorted_matrix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py index 1b36df52cbab..9f9431ad9469 100644 --- a/matrix/count_negative_numbers_in_sorted_matrix.py +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -145,7 +145,7 @@ def benchmark() -> None: print("Running benchmarks") setup = ( "from __main__ import count_negatives_binary_search,count_negatives_brute_force" - ",count_negatives_brute_force_with_break,generate_large_matrix" + ",count_negatives_brute_force_with_break,grid" ) for func in ( "count_negatives_binary_search", # 175.51 seconds From 97e2017d61b5f6d08df49c704ab9a778c4f3e676 Mon Sep 17 00:00:00 2001 From: CaedenPH Date: Sat, 10 Jun 2023 12:45:55 +0100 Subject: [PATCH 17/20] refactor: Use sum instead of large iteration --- matrix/count_negative_numbers_in_sorted_matrix.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py index 9f9431ad9469..ee28c2be8f47 100644 --- a/matrix/count_negative_numbers_in_sorted_matrix.py +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -97,12 +97,7 @@ def count_negatives_brute_force(grid: list[list[int]]) -> int: >>> count_negatives_brute_force([[7,7,6],[-1,-2,-3]]) 3 """ - total = 0 - for m in range(len(grid)): - for n in range(len(grid[m])): - if grid[m][n] < 0: - total += 1 - return total + return sum(number for row in grid for number in row if number < 0) def count_negatives_brute_force_with_break(grid: list[list[int]]) -> int: @@ -138,6 +133,8 @@ def generate_large_matrix() -> list[list[int]]: grid = generate_large_matrix() + + def benchmark() -> None: """Benchmark our functions next to each other""" from timeit import timeit From 0f21b1bc8376fbe91365011064da58ed0d9aa940 Mon Sep 17 00:00:00 2001 From: CaedenPH Date: Sat, 10 Jun 2023 12:48:37 +0100 Subject: [PATCH 18/20] refactor: Use len not sum --- matrix/count_negative_numbers_in_sorted_matrix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py index ee28c2be8f47..7122ebc739e0 100644 --- a/matrix/count_negative_numbers_in_sorted_matrix.py +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -97,7 +97,7 @@ def count_negatives_brute_force(grid: list[list[int]]) -> int: >>> count_negatives_brute_force([[7,7,6],[-1,-2,-3]]) 3 """ - return sum(number for row in grid for number in row if number < 0) + return len([number for row in grid for number in row if number < 0]) def count_negatives_brute_force_with_break(grid: list[list[int]]) -> int: From 605be4315eb14bb77f77120b934e8ea2802e3693 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sat, 10 Jun 2023 14:16:42 +0200 Subject: [PATCH 19/20] Update count_negative_numbers_in_sorted_matrix.py --- ...count_negative_numbers_in_sorted_matrix.py | 111 ++++++++---------- 1 file changed, 51 insertions(+), 60 deletions(-) diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py index 7122ebc739e0..0e5205f65475 100644 --- a/matrix/count_negative_numbers_in_sorted_matrix.py +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -2,10 +2,38 @@ Given an matrix of numbers in which all rows and all columns are sorted in decreasing order, return the number of negative numbers in grid. -Leetcode reference: https://leetcode.com/problems/count-negative-numbers-in-a-sorted-matrix +Reference: https://leetcode.com/problems/count-negative-numbers-in-a-sorted-matrix """ +def generate_large_matrix() -> list[list[int]]: + """ + >>> generate_large_matrix() # doctest: +ELLIPSIS + [[1000, ..., -999], [999, ..., -1001], ..., [2, ..., -1998]] + """ + return [list(range(1000 - i, -1000 - i, -1)) for i in range(1000)] + + +grid = generate_large_matrix() +test_grids = ( + [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]], + [[3,2],[1,0]], + [[7,7,6]], + [[7,7,6],[-1,-2,-3]], + grid +) + + +def validate_grid(grid: list[list[int]]) -> None: + """ + Validate that the rows and columns of the grid is sorted in decreasing order. + >>> for grid in test_grids: + ... validate_grid(grid) + """ + assert all(row == sorted(row, reverse=True) for row in grid) + assert all(list(col) == sorted(col, reverse=True) for col in zip(*grid)) + + def find_negative_index(array: list[int]) -> int: """ Find the smallest negative index @@ -34,8 +62,7 @@ def find_negative_index(array: list[int]) -> int: left = 0 right = len(array) - 1 - # Edge cases such as no values or - # all numbers are negative + # Edge cases such as no values or all numbers are negative. if not array or array[0] < 0: return 0 @@ -43,8 +70,7 @@ def find_negative_index(array: list[int]) -> int: mid = (left + right) // 2 num = array[mid] - # Num must be negative and the index about num - # must be greater than or equal to 0 + # Num must be negative and the index must be greater than or equal to 0. if num < 0 and array[mid - 1] >= 0: return mid @@ -52,26 +78,17 @@ def find_negative_index(array: list[int]) -> int: left = mid + 1 else: right = mid - 1 - # No negative numbers so return the last index - # of the array + 1 which is also the length + # No negative numbers so return the last index of the array + 1 which is the length. return len(array) def count_negatives_binary_search(grid: list[list[int]]) -> int: """ - An O(m logn) solution that uses binary search - in order to find the boundary between positive and - negative numbers - - >>> count_negatives_binary_search( - ... [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]]) - 8 - >>> count_negatives_binary_search([[3,2],[1,0]]) - 0 - >>> count_negatives_binary_search([[7,7,6]]) - 0 - >>> count_negatives_binary_search([[7,7,6],[-1,-2,-3]]) - 3 + An O(m logn) solution that uses binary search in order to find the boundary between + positive and negative numbers + + >>> [count_negatives_binary_search(grid) for grid in test_grids] + [8, 0, 0, 3, 1498500] """ total = 0 bound = len(grid[0]) @@ -84,36 +101,22 @@ def count_negatives_binary_search(grid: list[list[int]]) -> int: def count_negatives_brute_force(grid: list[list[int]]) -> int: """ - This solution is O(n^2) because it iterates through - every column and row. + This solution is O(n^2) because it iterates through every column and row. - >>> count_negatives_brute_force( - ... [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]]) - 8 - >>> count_negatives_brute_force([[3,2],[1,0]]) - 0 - >>> count_negatives_brute_force([[7,7,6]]) - 0 - >>> count_negatives_brute_force([[7,7,6],[-1,-2,-3]]) - 3 + >>> [count_negatives_brute_force(grid) for grid in test_grids] + [8, 0, 0, 3, 1498500] """ return len([number for row in grid for number in row if number < 0]) + def count_negatives_brute_force_with_break(grid: list[list[int]]) -> int: """ - Similar to the solution above, however uses break - in order to reduce the number of iterations + Similar to the brute force solution above but uses break in order to reduce the + number of iterations. - >>> count_negatives_brute_force_with_break( - ... [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]]) - 8 - >>> count_negatives_brute_force_with_break([[3,2],[1,0]]) - 0 - >>> count_negatives_brute_force_with_break([[7,7,6]]) - 0 - >>> count_negatives_brute_force_with_break([[7,7,6],[-1,-2,-3]]) - 3 + >>> [count_negatives_brute_force_with_break(grid) for grid in test_grids] + [8, 0, 0, 3, 1498500] """ total = 0 for row in grid: @@ -124,38 +127,26 @@ def count_negatives_brute_force_with_break(grid: list[list[int]]) -> int: return total -def generate_large_matrix() -> list[list[int]]: - """ - >>> generate_large_matrix() # doctest: +ELLIPSIS - [[1000, ..., -999], [999, ..., -1001], ..., [2, ..., -1998]] - """ - return [list(range(1000 - i, -1000 - i, -1)) for i in range(1000)] - - -grid = generate_large_matrix() - - def benchmark() -> None: """Benchmark our functions next to each other""" from timeit import timeit print("Running benchmarks") setup = ( - "from __main__ import count_negatives_binary_search,count_negatives_brute_force" - ",count_negatives_brute_force_with_break,grid" + "from __main__ import count_negatives_binary_search, " + "count_negatives_brute_force, count_negatives_brute_force_with_break, grid" ) for func in ( - "count_negatives_binary_search", # 175.51 seconds - "count_negatives_brute_force_with_break", # 271.04 seconds - "count_negatives_brute_force", # 646.65 seconds + "count_negatives_binary_search", # took 0.7727 seconds + "count_negatives_brute_force_with_break", # took 4.6505 seconds + "count_negatives_brute_force", # took 12.8160 seconds ): time = timeit(f"{func}(grid=grid)", setup=setup, number=500) - print(f"{func}() took {time} seconds") + print(f"{func}() took {time:0.4f} seconds") if __name__ == "__main__": import doctest doctest.testmod() - benchmark() From 21dbc02d30bfab25c8a9e7c6d61b2337d664ddb4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 10 Jun 2023 12:17:14 +0000 Subject: [PATCH 20/20] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- matrix/count_negative_numbers_in_sorted_matrix.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/matrix/count_negative_numbers_in_sorted_matrix.py b/matrix/count_negative_numbers_in_sorted_matrix.py index 0e5205f65475..2799ff3b45fe 100644 --- a/matrix/count_negative_numbers_in_sorted_matrix.py +++ b/matrix/count_negative_numbers_in_sorted_matrix.py @@ -16,11 +16,11 @@ def generate_large_matrix() -> list[list[int]]: grid = generate_large_matrix() test_grids = ( - [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]], - [[3,2],[1,0]], - [[7,7,6]], - [[7,7,6],[-1,-2,-3]], - grid + [[4, 3, 2, -1], [3, 2, 1, -1], [1, 1, -1, -2], [-1, -1, -2, -3]], + [[3, 2], [1, 0]], + [[7, 7, 6]], + [[7, 7, 6], [-1, -2, -3]], + grid, ) @@ -109,7 +109,6 @@ def count_negatives_brute_force(grid: list[list[int]]) -> int: return len([number for row in grid for number in row if number < 0]) - def count_negatives_brute_force_with_break(grid: list[list[int]]) -> int: """ Similar to the brute force solution above but uses break in order to reduce the