diff --git a/DIRECTORY.md b/DIRECTORY.md index 60ece2b8..caaa5692 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -138,8 +138,24 @@ * Spread Stones * [Test Minimum Moves To Spread Stones](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/greedy/spread_stones/test_minimum_moves_to_spread_stones.py) * Heap + * Longest Happy String + * [Test Longest Happy String](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/heap/longest_happy_string/test_longest_happy_string.py) + * Maximal Score After K Operations + * [Test Maximal Score](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/heap/maximal_score_after_k_operations/test_maximal_score.py) + * Maximum Subsequence Score + * [Test Max Subsequence Score](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/heap/maximum_subsequence_score/test_max_subsequence_score.py) + * Min Cost Hire K Workers + * [Test Min Cost To Hire Workers](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/heap/min_cost_hire_k_workers/test_min_cost_to_hire_workers.py) + * Min Cost To Connect Sticks + * [Test Min Cost Connect Sticks](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/heap/min_cost_to_connect_sticks/test_min_cost_connect_sticks.py) * Schedule Tasks * [Test Schedule Tasks On Minimum Machines](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/heap/schedule_tasks/test_schedule_tasks_on_minimum_machines.py) + * Topkclosesttoorigin + * [Test Top K Closest To Origin](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/heap/topkclosesttoorigin/test_top_k_closest_to_origin.py) + * Topklargest + * [Test Top K Largest Elements](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/heap/topklargest/test_top_k_largest_elements.py) + * Total Cost Hire K Workers + * [Test Total Cost Hire K Workers](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/heap/total_cost_hire_k_workers/test_total_cost_hire_k_workers.py) * Huffman * [Decoding](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/huffman/decoding.py) * [Encoding](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/huffman/encoding.py) @@ -173,6 +189,9 @@ * [Test Task Scheduler](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/intervals/task_scheduler/test_task_scheduler.py) * Josephus Circle * [Test Josephus Circle](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/josephus_circle/test_josephus_circle.py) + * Matrix + * Isvalidsudoku + * [Test Is Valid Sudoku](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/matrix/isvalidsudoku/test_is_valid_sudoku.py) * Memoization * [Fibonacci](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/memoization/fibonacci.py) * [Petethebaker](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/petethebaker.py) @@ -670,17 +689,6 @@ * [Test Find Difference](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/hashmap/find_difference_of_two_arrays/test_find_difference.py) * Unique Number Of Occurrences * [Test Unique Occurrences](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/hashmap/unique_number_of_occurrences/test_unique_occurrences.py) - * Heap - * Maximal Score After K Operations - * [Test Maximal Score](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/heap/maximal_score_after_k_operations/test_maximal_score.py) - * Maximum Subsequence Score - * [Test Max Subsequence Score](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/heap/maximum_subsequence_score/test_max_subsequence_score.py) - * Min Cost Hire K Workers - * [Test Min Cost To Hire Workers](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/heap/min_cost_hire_k_workers/test_min_cost_to_hire_workers.py) - * Min Cost To Connect Sticks - * [Test Min Cost Connect Sticks](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/heap/min_cost_to_connect_sticks/test_min_cost_connect_sticks.py) - * Total Cost Hire K Workers - * [Test Total Cost Hire K Workers](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/heap/total_cost_hire_k_workers/test_total_cost_hire_k_workers.py) * Hidden Cubic Numbers * [Hidden Cubic Numbers](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/hidden_cubic_numbers/hidden_cubic_numbers.py) * Matrix In Spiral Form @@ -861,8 +869,6 @@ * [Test Longest Common Prefix](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/longest_common_prefix/test_longest_common_prefix.py) * Longest Common Suffix Queries * [Test Longest Common Suffix Queries](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/longest_common_suffix_queries/test_longest_common_suffix_queries.py) - * Longest Happy String - * [Test Longest Happy String](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/longest_happy_string/test_longest_happy_string.py) * Longest Self Contained Substring * [Test Longest Self Contained Substring](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/longest_self_contained_substring/test_longest_self_contained_substring.py) * Look And Say Sequence diff --git a/puzzles/heap/__init__.py b/algorithms/dfs/__init__.py similarity index 100% rename from puzzles/heap/__init__.py rename to algorithms/dfs/__init__.py diff --git a/pystrings/longest_happy_string/README.md b/algorithms/heap/longest_happy_string/README.md similarity index 72% rename from pystrings/longest_happy_string/README.md rename to algorithms/heap/longest_happy_string/README.md index 49cd3b83..633505c4 100644 --- a/pystrings/longest_happy_string/README.md +++ b/algorithms/heap/longest_happy_string/README.md @@ -22,9 +22,9 @@ strings, return any one of them. If no such string can be formed, return an empt ## Examples -![Example 1](./images/examples/longest_happy_string_example_1.png) -![Example 2](./images/examples/longest_happy_string_example_2.png) -![Example 3](./images/examples/longest_happy_string_example_3.png) +![Example 1](images/examples/longest_happy_string_example_1.png) +![Example 2](images/examples/longest_happy_string_example_2.png) +![Example 3](images/examples/longest_happy_string_example_3.png) ## Solution @@ -55,21 +55,21 @@ Note: In Python, strings are immutable, so we construct the result as a list and Let’s look at the following illustration to get a better understanding of the solution: -![Longest Happy String Solution 1](./images/solutions/longest_happy_string_solution_1.png) -![Longest Happy String Solution 2](./images/solutions/longest_happy_string_solution_2.png) -![Longest Happy String Solution 3](./images/solutions/longest_happy_string_solution_3.png) -![Longest Happy String Solution 4](./images/solutions/longest_happy_string_solution_4.png) -![Longest Happy String Solution 5](./images/solutions/longest_happy_string_solution_5.png) -![Longest Happy String Solution 6](./images/solutions/longest_happy_string_solution_6.png) -![Longest Happy String Solution 7](./images/solutions/longest_happy_string_solution_7.png) -![Longest Happy String Solution 8](./images/solutions/longest_happy_string_solution_8.png) -![Longest Happy String Solution 9](./images/solutions/longest_happy_string_solution_9.png) -![Longest Happy String Solution 10](./images/solutions/longest_happy_string_solution_10.png) -![Longest Happy String Solution 11](./images/solutions/longest_happy_string_solution_11.png) -![Longest Happy String Solution 12](./images/solutions/longest_happy_string_solution_12.png) -![Longest Happy String Solution 13](./images/solutions/longest_happy_string_solution_13.png) -![Longest Happy String Solution 14](./images/solutions/longest_happy_string_solution_14.png) -![Longest Happy String Solution 15](./images/solutions/longest_happy_string_solution_15.png) +![Longest Happy String Solution 1](images/solutions/longest_happy_string_solution_1.png) +![Longest Happy String Solution 2](images/solutions/longest_happy_string_solution_2.png) +![Longest Happy String Solution 3](images/solutions/longest_happy_string_solution_3.png) +![Longest Happy String Solution 4](images/solutions/longest_happy_string_solution_4.png) +![Longest Happy String Solution 5](images/solutions/longest_happy_string_solution_5.png) +![Longest Happy String Solution 6](images/solutions/longest_happy_string_solution_6.png) +![Longest Happy String Solution 7](images/solutions/longest_happy_string_solution_7.png) +![Longest Happy String Solution 8](images/solutions/longest_happy_string_solution_8.png) +![Longest Happy String Solution 9](images/solutions/longest_happy_string_solution_9.png) +![Longest Happy String Solution 10](images/solutions/longest_happy_string_solution_10.png) +![Longest Happy String Solution 11](images/solutions/longest_happy_string_solution_11.png) +![Longest Happy String Solution 12](images/solutions/longest_happy_string_solution_12.png) +![Longest Happy String Solution 13](images/solutions/longest_happy_string_solution_13.png) +![Longest Happy String Solution 14](images/solutions/longest_happy_string_solution_14.png) +![Longest Happy String Solution 15](images/solutions/longest_happy_string_solution_15.png) ### Time complexity diff --git a/pystrings/longest_happy_string/__init__.py b/algorithms/heap/longest_happy_string/__init__.py similarity index 94% rename from pystrings/longest_happy_string/__init__.py rename to algorithms/heap/longest_happy_string/__init__.py index 7da0fde4..c06f2e6a 100644 --- a/pystrings/longest_happy_string/__init__.py +++ b/algorithms/heap/longest_happy_string/__init__.py @@ -20,8 +20,8 @@ def longest_diverse_string(a: int, b: int, c: int) -> str: # Process the heap until it's empty or no valid character can be added while max_heap: # Pop the character with the highest remaining frequency - count, character = heappop(max_heap) - count = -count # Convert back to positive + negative_count, character = heappop(max_heap) + count = -negative_count # Convert back to positive # Check if adding this character violates the "no three consecutive" rule if len(result) >= 2 and result[-1] == character and result[-2] == character: diff --git a/pystrings/longest_happy_string/images/examples/longest_happy_string_example_1.png b/algorithms/heap/longest_happy_string/images/examples/longest_happy_string_example_1.png similarity index 100% rename from pystrings/longest_happy_string/images/examples/longest_happy_string_example_1.png rename to algorithms/heap/longest_happy_string/images/examples/longest_happy_string_example_1.png diff --git a/pystrings/longest_happy_string/images/examples/longest_happy_string_example_2.png b/algorithms/heap/longest_happy_string/images/examples/longest_happy_string_example_2.png similarity index 100% rename from pystrings/longest_happy_string/images/examples/longest_happy_string_example_2.png rename to algorithms/heap/longest_happy_string/images/examples/longest_happy_string_example_2.png diff --git a/pystrings/longest_happy_string/images/examples/longest_happy_string_example_3.png b/algorithms/heap/longest_happy_string/images/examples/longest_happy_string_example_3.png similarity index 100% rename from pystrings/longest_happy_string/images/examples/longest_happy_string_example_3.png rename to algorithms/heap/longest_happy_string/images/examples/longest_happy_string_example_3.png diff --git a/pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_1.png b/algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_1.png similarity index 100% rename from pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_1.png rename to algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_1.png diff --git a/pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_10.png b/algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_10.png similarity index 100% rename from pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_10.png rename to algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_10.png diff --git a/pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_11.png b/algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_11.png similarity index 100% rename from pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_11.png rename to algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_11.png diff --git a/pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_12.png b/algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_12.png similarity index 100% rename from pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_12.png rename to algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_12.png diff --git a/pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_13.png b/algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_13.png similarity index 100% rename from pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_13.png rename to algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_13.png diff --git a/pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_14.png b/algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_14.png similarity index 100% rename from pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_14.png rename to algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_14.png diff --git a/pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_15.png b/algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_15.png similarity index 100% rename from pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_15.png rename to algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_15.png diff --git a/pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_2.png b/algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_2.png similarity index 100% rename from pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_2.png rename to algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_2.png diff --git a/pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_3.png b/algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_3.png similarity index 100% rename from pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_3.png rename to algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_3.png diff --git a/pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_4.png b/algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_4.png similarity index 100% rename from pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_4.png rename to algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_4.png diff --git a/pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_5.png b/algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_5.png similarity index 100% rename from pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_5.png rename to algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_5.png diff --git a/pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_6.png b/algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_6.png similarity index 100% rename from pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_6.png rename to algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_6.png diff --git a/pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_7.png b/algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_7.png similarity index 100% rename from pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_7.png rename to algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_7.png diff --git a/pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_8.png b/algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_8.png similarity index 100% rename from pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_8.png rename to algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_8.png diff --git a/pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_9.png b/algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_9.png similarity index 100% rename from pystrings/longest_happy_string/images/solutions/longest_happy_string_solution_9.png rename to algorithms/heap/longest_happy_string/images/solutions/longest_happy_string_solution_9.png diff --git a/pystrings/longest_happy_string/test_longest_happy_string.py b/algorithms/heap/longest_happy_string/test_longest_happy_string.py similarity index 90% rename from pystrings/longest_happy_string/test_longest_happy_string.py rename to algorithms/heap/longest_happy_string/test_longest_happy_string.py index 17975251..edb4bbba 100644 --- a/pystrings/longest_happy_string/test_longest_happy_string.py +++ b/algorithms/heap/longest_happy_string/test_longest_happy_string.py @@ -1,6 +1,6 @@ import unittest from parameterized import parameterized -from pystrings.longest_happy_string import longest_diverse_string +from algorithms.heap.longest_happy_string import longest_diverse_string class LongestHappyStringTestCase(unittest.TestCase): diff --git a/puzzles/heap/maximal_score_after_k_operations/README.md b/algorithms/heap/maximal_score_after_k_operations/README.md similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/README.md rename to algorithms/heap/maximal_score_after_k_operations/README.md diff --git a/puzzles/heap/maximal_score_after_k_operations/__init__.py b/algorithms/heap/maximal_score_after_k_operations/__init__.py similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/__init__.py rename to algorithms/heap/maximal_score_after_k_operations/__init__.py diff --git a/puzzles/heap/maximal_score_after_k_operations/images/examples/maximal_score_after_k_operations_example_1.png b/algorithms/heap/maximal_score_after_k_operations/images/examples/maximal_score_after_k_operations_example_1.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/examples/maximal_score_after_k_operations_example_1.png rename to algorithms/heap/maximal_score_after_k_operations/images/examples/maximal_score_after_k_operations_example_1.png diff --git a/puzzles/heap/maximal_score_after_k_operations/images/examples/maximal_score_after_k_operations_example_2.png b/algorithms/heap/maximal_score_after_k_operations/images/examples/maximal_score_after_k_operations_example_2.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/examples/maximal_score_after_k_operations_example_2.png rename to algorithms/heap/maximal_score_after_k_operations/images/examples/maximal_score_after_k_operations_example_2.png diff --git a/puzzles/heap/maximal_score_after_k_operations/images/examples/maximal_score_after_k_operations_example_3.png b/algorithms/heap/maximal_score_after_k_operations/images/examples/maximal_score_after_k_operations_example_3.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/examples/maximal_score_after_k_operations_example_3.png rename to algorithms/heap/maximal_score_after_k_operations/images/examples/maximal_score_after_k_operations_example_3.png diff --git a/puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_1.png b/algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_1.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_1.png rename to algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_1.png diff --git a/puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_10.png b/algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_10.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_10.png rename to algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_10.png diff --git a/puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_11.png b/algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_11.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_11.png rename to algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_11.png diff --git a/puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_12.png b/algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_12.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_12.png rename to algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_12.png diff --git a/puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_13.png b/algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_13.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_13.png rename to algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_13.png diff --git a/puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_14.png b/algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_14.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_14.png rename to algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_14.png diff --git a/puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_15.png b/algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_15.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_15.png rename to algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_15.png diff --git a/puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_2.png b/algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_2.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_2.png rename to algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_2.png diff --git a/puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_3.png b/algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_3.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_3.png rename to algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_3.png diff --git a/puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_4.png b/algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_4.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_4.png rename to algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_4.png diff --git a/puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_5.png b/algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_5.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_5.png rename to algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_5.png diff --git a/puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_6.png b/algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_6.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_6.png rename to algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_6.png diff --git a/puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_7.png b/algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_7.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_7.png rename to algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_7.png diff --git a/puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_8.png b/algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_8.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_8.png rename to algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_8.png diff --git a/puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_9.png b/algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_9.png similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_9.png rename to algorithms/heap/maximal_score_after_k_operations/images/solution/maximal_score_after_k_operations_solution_9.png diff --git a/puzzles/heap/maximal_score_after_k_operations/test_maximal_score.py b/algorithms/heap/maximal_score_after_k_operations/test_maximal_score.py similarity index 100% rename from puzzles/heap/maximal_score_after_k_operations/test_maximal_score.py rename to algorithms/heap/maximal_score_after_k_operations/test_maximal_score.py diff --git a/puzzles/heap/maximum_subsequence_score/README.md b/algorithms/heap/maximum_subsequence_score/README.md similarity index 100% rename from puzzles/heap/maximum_subsequence_score/README.md rename to algorithms/heap/maximum_subsequence_score/README.md diff --git a/puzzles/heap/maximum_subsequence_score/__init__.py b/algorithms/heap/maximum_subsequence_score/__init__.py similarity index 100% rename from puzzles/heap/maximum_subsequence_score/__init__.py rename to algorithms/heap/maximum_subsequence_score/__init__.py diff --git a/puzzles/heap/maximum_subsequence_score/test_max_subsequence_score.py b/algorithms/heap/maximum_subsequence_score/test_max_subsequence_score.py similarity index 100% rename from puzzles/heap/maximum_subsequence_score/test_max_subsequence_score.py rename to algorithms/heap/maximum_subsequence_score/test_max_subsequence_score.py diff --git a/puzzles/heap/min_cost_hire_k_workers/README.md b/algorithms/heap/min_cost_hire_k_workers/README.md similarity index 100% rename from puzzles/heap/min_cost_hire_k_workers/README.md rename to algorithms/heap/min_cost_hire_k_workers/README.md diff --git a/puzzles/heap/min_cost_hire_k_workers/__init__.py b/algorithms/heap/min_cost_hire_k_workers/__init__.py similarity index 100% rename from puzzles/heap/min_cost_hire_k_workers/__init__.py rename to algorithms/heap/min_cost_hire_k_workers/__init__.py diff --git a/puzzles/heap/min_cost_hire_k_workers/test_min_cost_to_hire_workers.py b/algorithms/heap/min_cost_hire_k_workers/test_min_cost_to_hire_workers.py similarity index 100% rename from puzzles/heap/min_cost_hire_k_workers/test_min_cost_to_hire_workers.py rename to algorithms/heap/min_cost_hire_k_workers/test_min_cost_to_hire_workers.py diff --git a/puzzles/heap/min_cost_to_connect_sticks/README.md b/algorithms/heap/min_cost_to_connect_sticks/README.md similarity index 70% rename from puzzles/heap/min_cost_to_connect_sticks/README.md rename to algorithms/heap/min_cost_to_connect_sticks/README.md index a13d3acf..4ecdbc50 100644 --- a/puzzles/heap/min_cost_to_connect_sticks/README.md +++ b/algorithms/heap/min_cost_to_connect_sticks/README.md @@ -16,7 +16,7 @@ Constraints: ## Examples -![Example 1](./images/examples/min_cost_to_connect_sticks_1.png) -![Example 2](./images/examples/min_cost_to_connect_sticks_2.png) -![Example 3](./images/examples/min_cost_to_connect_sticks_3.png) -![Example 4](./images/examples/min_cost_to_connect_sticks_4.png) +![Example 1](images/examples/min_cost_to_connect_sticks_1.png) +![Example 2](images/examples/min_cost_to_connect_sticks_2.png) +![Example 3](images/examples/min_cost_to_connect_sticks_3.png) +![Example 4](images/examples/min_cost_to_connect_sticks_4.png) diff --git a/puzzles/heap/min_cost_to_connect_sticks/__init__.py b/algorithms/heap/min_cost_to_connect_sticks/__init__.py similarity index 100% rename from puzzles/heap/min_cost_to_connect_sticks/__init__.py rename to algorithms/heap/min_cost_to_connect_sticks/__init__.py diff --git a/puzzles/heap/min_cost_to_connect_sticks/images/examples/min_cost_to_connect_sticks_1.png b/algorithms/heap/min_cost_to_connect_sticks/images/examples/min_cost_to_connect_sticks_1.png similarity index 100% rename from puzzles/heap/min_cost_to_connect_sticks/images/examples/min_cost_to_connect_sticks_1.png rename to algorithms/heap/min_cost_to_connect_sticks/images/examples/min_cost_to_connect_sticks_1.png diff --git a/puzzles/heap/min_cost_to_connect_sticks/images/examples/min_cost_to_connect_sticks_2.png b/algorithms/heap/min_cost_to_connect_sticks/images/examples/min_cost_to_connect_sticks_2.png similarity index 100% rename from puzzles/heap/min_cost_to_connect_sticks/images/examples/min_cost_to_connect_sticks_2.png rename to algorithms/heap/min_cost_to_connect_sticks/images/examples/min_cost_to_connect_sticks_2.png diff --git a/puzzles/heap/min_cost_to_connect_sticks/images/examples/min_cost_to_connect_sticks_3.png b/algorithms/heap/min_cost_to_connect_sticks/images/examples/min_cost_to_connect_sticks_3.png similarity index 100% rename from puzzles/heap/min_cost_to_connect_sticks/images/examples/min_cost_to_connect_sticks_3.png rename to algorithms/heap/min_cost_to_connect_sticks/images/examples/min_cost_to_connect_sticks_3.png diff --git a/puzzles/heap/min_cost_to_connect_sticks/images/examples/min_cost_to_connect_sticks_4.png b/algorithms/heap/min_cost_to_connect_sticks/images/examples/min_cost_to_connect_sticks_4.png similarity index 100% rename from puzzles/heap/min_cost_to_connect_sticks/images/examples/min_cost_to_connect_sticks_4.png rename to algorithms/heap/min_cost_to_connect_sticks/images/examples/min_cost_to_connect_sticks_4.png diff --git a/puzzles/heap/min_cost_to_connect_sticks/test_min_cost_connect_sticks.py b/algorithms/heap/min_cost_to_connect_sticks/test_min_cost_connect_sticks.py similarity index 100% rename from puzzles/heap/min_cost_to_connect_sticks/test_min_cost_connect_sticks.py rename to algorithms/heap/min_cost_to_connect_sticks/test_min_cost_connect_sticks.py diff --git a/algorithms/heap/topkclosesttoorigin/README.md b/algorithms/heap/topkclosesttoorigin/README.md new file mode 100644 index 00000000..4fd707d0 --- /dev/null +++ b/algorithms/heap/topkclosesttoorigin/README.md @@ -0,0 +1,104 @@ +# K Closest Points to Origin + +Given a list of points in the form [[x1, y1], [x2, y2], ... [xn, yn]] and an integer k, find the k closest points to the +origin (0, 0) on the 2D plane. + +The distance between two points (x, y) and (a, b) is calculated using the formula: + +√(x1 - a2)2 + (y1 - b2)2 + +Return the k closest points in any order. + +## Examples + +```text +Input: + +points = [[3,4],[2,2],[1,1],[0,0],[5,5]] +k = 3 + +Output: +[[2,2],[1,1],[0,0]] + +Also Valid: + +[[2,2],[0,0],[1,1]] +[[1,1],[0,0],[2,2]] +[[1,1],[2,2],[0,0]] +... +[[0,0],[1,1],[2,2]] +``` + +![Example 1](./images/examples/top_k_closest_to_origin_example_1.png) + +```text +Input: points = [[3,3],[5,-1],[-2,4]], k = 2 +Output: [[3,3],[-2,4]] +Explanation: The answer [[-2,4],[3,3]] would also be accepted. +``` + +```text +Input: points = [[1,3],[-2,2]], k = 1 +Output: [[-2,2]] + +Explanation: +The distance between (1, 3) and the origin is sqrt(10). +The distance between (-2, 2) and the origin is sqrt(8). +Since sqrt(8) < sqrt(10), (-2, 2) is closer to the origin. +We only want the closest k = 1 points from the origin, so the answer is just [[-2,2]]. +``` + +## Solution + +- [Approach 1](#approach-1-sorting) +- [Approach 2](#approach-2-max-heap) + +### Approach 1: Sorting + +The simplest approach is to sort calculate the distance of each point from the origin and sort the points based on their +distance. This approach has a time complexity of O(n log n) where n is the number of points in the array, and a space +complexity of O(n) (to store the sorted array of distances). + +### Approach 2: Max Heap + +This problem can be solved using a similar approach to the one used to solve [Kth Largest Element in an Array](../topklargest/README.md). The key +difference is that we need to store the k closest points to the origin, rather than the k largest elements. Since we are +looking for the k smallest elements, we need a max-heap, rather than a min-heap. + +By default, python's heapq module implements a min-heap, but we can make it behave like a max-heap by negating the values +of everything we push onto it. + +We add the first k points to the heap by pushing a tuple containing the negative of the distance from the origin, and the +index of the point. After that is finished, our heap contains the k closest points to the origin that we've seen so far, +with the point furthest from the origin at the root of the heap. + +For each point after the first k, we calculate the distance from the origin and compare it with the root of the heap. If +the current point is closer to the origin than the root of the heap, we pop the root and push the current point into the +heap. This way, the heap will always contain the k closest points to the origin we've seen so far. + +At the end of the iteration, the heap will contain the k closest points to the origin. We can iterate over each point in +the heap and return the point associated with each tuple. + +![Solution 0](./images/solutions/top_k_closest_to_origin_solution_0.png) +![Solution 1](./images/solutions/top_k_closest_to_origin_solution_1.png) +![Solution 2](./images/solutions/top_k_closest_to_origin_solution_2.png) +![Solution 3](./images/solutions/top_k_closest_to_origin_solution_3.png) +![Solution 4](./images/solutions/top_k_closest_to_origin_solution_4.png) +![Solution 5](./images/solutions/top_k_closest_to_origin_solution_5.png) +![Solution 6](./images/solutions/top_k_closest_to_origin_solution_6.png) +![Solution 7](./images/solutions/top_k_closest_to_origin_solution_7.png) +![Solution 8](./images/solutions/top_k_closest_to_origin_solution_8.png) +![Solution 9](./images/solutions/top_k_closest_to_origin_solution_9.png) +![Solution 10](./images/solutions/top_k_closest_to_origin_solution_10.png) +![Solution 11](./images/solutions/top_k_closest_to_origin_solution_11.png) + +#### Complexity Analysis + +##### Time Complexity: O(n log k) + +Where n is the number of points in the array and k is the input parameter. We iterate over +all points, and in the worst case, we both push and pop each point from the heap, which takes O(log k) time per point. + +##### Space Complexity: O(k) + +Where k is the input parameter. The space is used by the heap to store the k closest points to the origin. diff --git a/algorithms/heap/topkclosesttoorigin/__init__.py b/algorithms/heap/topkclosesttoorigin/__init__.py new file mode 100644 index 00000000..ec62166d --- /dev/null +++ b/algorithms/heap/topkclosesttoorigin/__init__.py @@ -0,0 +1,36 @@ +from typing import List, Tuple +import heapq + + +def k_closest_to_origin(points: List[List[int]], k: int) -> List[List[int]]: + # Max heap will store the top k points closest to the origin in the form (-distance, idx). The distance is negated + # because in Python, the heapq module uses min-heap by default. Negating values gives us a maximum heap. + # We store the idx of the point for later retrieval from the points array passed in + max_heap: List[Tuple[int, int]] = [] + + for idx, point in enumerate(points): + x, y = point + # calculate the distance for this point from the origin + distance = x * x + y * y + + # If the contents of the heap are less than the desired top k, then we add the current point's distance and idx + if len(max_heap) < k: + heapq.heappush(max_heap, (-distance, idx)) + # We check if the calculated distance of this point is less than the top element in the heap. If this point + # is closer to the origin that what is at the root of the heap, we pop the root of the heap and add this + # new distance and index. + # Note the negation here again to get the actual distance + elif distance < -max_heap[0][0]: + heapq.heappushpop(max_heap, (-distance, idx)) + + # Return the top k points closest to origin. We use 1 to get the index of the point from the original points list + # as that is what is stored in the max heap + return [points[point[1]] for point in max_heap] + + +def k_closest_to_origin_sorting(points: List[List[int]], k: int) -> List[List[int]]: + # Sort the points by the distance from the origin. This incurs a cost of O(n log(n)) and space cost of O(n) due to + # timsort + sorted_points = sorted(points, key=lambda p: p[0] ** 2 + p[1] ** 2) + # Retrieve the top k points closest to the origin + return sorted_points[:k] diff --git a/algorithms/heap/topkclosesttoorigin/images/examples/top_k_closest_to_origin_example_1.png b/algorithms/heap/topkclosesttoorigin/images/examples/top_k_closest_to_origin_example_1.png new file mode 100644 index 00000000..44f52f8a Binary files /dev/null and b/algorithms/heap/topkclosesttoorigin/images/examples/top_k_closest_to_origin_example_1.png differ diff --git a/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_0.png b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_0.png new file mode 100644 index 00000000..e8a83745 Binary files /dev/null and b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_0.png differ diff --git a/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_1.png b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_1.png new file mode 100644 index 00000000..ed631424 Binary files /dev/null and b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_1.png differ diff --git a/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_10.png b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_10.png new file mode 100644 index 00000000..bf38ea5b Binary files /dev/null and b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_10.png differ diff --git a/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_11.png b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_11.png new file mode 100644 index 00000000..3c75da67 Binary files /dev/null and b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_11.png differ diff --git a/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_2.png b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_2.png new file mode 100644 index 00000000..c358276e Binary files /dev/null and b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_2.png differ diff --git a/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_3.png b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_3.png new file mode 100644 index 00000000..055f4295 Binary files /dev/null and b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_3.png differ diff --git a/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_4.png b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_4.png new file mode 100644 index 00000000..fea681b5 Binary files /dev/null and b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_4.png differ diff --git a/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_5.png b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_5.png new file mode 100644 index 00000000..7cf496a4 Binary files /dev/null and b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_5.png differ diff --git a/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_6.png b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_6.png new file mode 100644 index 00000000..610a3794 Binary files /dev/null and b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_6.png differ diff --git a/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_7.png b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_7.png new file mode 100644 index 00000000..03603b98 Binary files /dev/null and b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_7.png differ diff --git a/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_8.png b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_8.png new file mode 100644 index 00000000..582f5847 Binary files /dev/null and b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_8.png differ diff --git a/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_9.png b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_9.png new file mode 100644 index 00000000..d92f42b9 Binary files /dev/null and b/algorithms/heap/topkclosesttoorigin/images/solutions/top_k_closest_to_origin_solution_9.png differ diff --git a/algorithms/heap/topkclosesttoorigin/test_top_k_closest_to_origin.py b/algorithms/heap/topkclosesttoorigin/test_top_k_closest_to_origin.py new file mode 100644 index 00000000..de979b30 --- /dev/null +++ b/algorithms/heap/topkclosesttoorigin/test_top_k_closest_to_origin.py @@ -0,0 +1,39 @@ +import unittest +from typing import List +from parameterized import parameterized +from algorithms.heap.topkclosesttoorigin import ( + k_closest_to_origin, + k_closest_to_origin_sorting, +) + +TOP_K_CLOSEST_TO_ORIGIN = [ + ([[3, 4], [2, 2], [1, 1], [0, 0], [5, 5]], 3, [[2, 2], [1, 1], [0, 0]]), + ([[1, 3], [-2, 2]], 1, [[-2, 2]]), + ([[3, 3], [5, -1], [-2, 4]], 2, [[3, 3], [-2, 4]]), +] + + +class TopKClosestToOriginTestCase(unittest.TestCase): + @parameterized.expand(TOP_K_CLOSEST_TO_ORIGIN) + def test_top_k_closest_to_origin( + self, points: List[List[int]], k: int, expected: List[List[int]] + ): + actual = k_closest_to_origin(points, k) + + sorted_expected = sorted(expected, key=lambda x: (x[0], x[1])) + sorted_actual = sorted(actual, key=lambda x: (x[0], x[1])) + self.assertEqual(sorted_expected, sorted_actual) + + @parameterized.expand(TOP_K_CLOSEST_TO_ORIGIN) + def test_top_k_closest_to_origin_sorting( + self, points: List[List[int]], k: int, expected: List[List[int]] + ): + actual = k_closest_to_origin_sorting(points, k) + + sorted_expected = sorted(expected, key=lambda x: x[0]) + sorted_actual = sorted(actual, key=lambda x: x[0]) + self.assertEqual(sorted_expected, sorted_actual) + + +if __name__ == "__main__": + unittest.main() diff --git a/pymath/topkfrequentelements/README.md b/algorithms/heap/topkfrequentelements/README.md similarity index 100% rename from pymath/topkfrequentelements/README.md rename to algorithms/heap/topkfrequentelements/README.md diff --git a/pymath/topkfrequentelements/__init__.py b/algorithms/heap/topkfrequentelements/__init__.py similarity index 100% rename from pymath/topkfrequentelements/__init__.py rename to algorithms/heap/topkfrequentelements/__init__.py diff --git a/algorithms/heap/topklargest/README.md b/algorithms/heap/topklargest/README.md new file mode 100644 index 00000000..aa97298e --- /dev/null +++ b/algorithms/heap/topklargest/README.md @@ -0,0 +1,106 @@ +# Top-K Largest Elements in an Array + +Given an integer array nums, return the 3 largest elements in the array in any order. + +## Example + +```text +Input: nums = [9, 3, 7, 1, -2, 6, 8] +Output: [8, 7, 9] +# or [7, 9, 8] or [9, 7, 8] ... +``` + +## Solution + +Here's how we can solve this problem using a min-heap: + +- Create a min-heap that stores the first 3 elements of the array. These represent the 3 largest elements we have seen so + far, with the smallest of the 3 at the root of the heap. + ![Solution 1](./images/solutions/top_k_largest_element_in_array_solution_1.png) + +- Iterate through the remaining elements in the array. + - If the current element is larger than the root of the heap, pop the root and push the current element into the heap. + - Otherwise, continue to the next element. + + ![Solution 2](./images/solutions/top_k_largest_element_in_array_solution_2.png) + ![Solution 3](./images/solutions/top_k_largest_element_in_array_solution_3.png) + ![Solution 4](./images/solutions/top_k_largest_element_in_array_solution_4.png) + ![Solution 5](./images/solutions/top_k_largest_element_in_array_solution_5.png) + +After iterating through all the elements, the heap contains the 3 largest elements in the array. + +### Complexity Analysis + +#### Time Complexity Breakdown + +- The heapify function takes O(3) = O(1) time +- We iterate through all elements in the array once: O(n) time +- The heappop and heappush operations take O(log 3) = O(1) time each + +#### Space Complexity + +- We use a heap of size 3 to store the 3 largest elements: O(3) = O(1) space +- The algorithm uses constant space regardless of input size + +Note: The time and space complexity become more interesting when 3 is a variable number k. + +--- + +# Kth Largest Element in an Array + +Write a function that takes an array of unsorted integers nums and an integer k, and returns the kth largest element in +the array. This function should run in O(n log k) time, where n is the length of the array. + +## Examples + +```text +Input: +nums = [5, 3, 2, 1, 4] +k = 2 + +Output: 4 +``` + +## Solutions + +- [Approach 1](#approach-1-sorting) +- [Approach 2](#approach-2-min-heap) + +### Approach 1: Sorting + +The simplest approach is to sort the array in descending order and return the kth element. This approach has a time +complexity of O(n log n) where n is the number of elements in the array, and a space complexity of O(1). + +### Approach 2: Min Heap + +By using a min-heap, we can reduce the time complexity to O(n log k), where n is the number of elements in the array and +k is the value of k. +The idea behind this solution is to iterate over the elements in the array while storing the k largest elements we've +seen so far in a min-heap. At each element, we check if it is greater than the smallest element (the root) of the heap. +If it is, we pop the smallest element from the heap and push the current element into the heap. This way, the heap will +always contain the k largest elements we've seen so far. +After iterating over all the elements, the root of the heap will be the kth largest element in the array. + +![Solution 2.1](./images/solutions/kth_largest_element_in_array_solution_1.png) +![Solution 2.2](./images/solutions/kth_largest_element_in_array_solution_2.png) +![Solution 2.3](./images/solutions/kth_largest_element_in_array_solution_3.png) +![Solution 2.4](./images/solutions/kth_largest_element_in_array_solution_4.png) +![Solution 2.5](./images/solutions/kth_largest_element_in_array_solution_5.png) +![Solution 2.6](./images/solutions/kth_largest_element_in_array_solution_6.png) +![Solution 2.7](./images/solutions/kth_largest_element_in_array_solution_7.png) +![Solution 2.8](./images/solutions/kth_largest_element_in_array_solution_8.png) +![Solution 2.9](./images/solutions/kth_largest_element_in_array_solution_9.png) +![Solution 2.10](./images/solutions/kth_largest_element_in_array_solution_10.png) +![Solution 2.11](./images/solutions/kth_largest_element_in_array_solution_11.png) + +#### Complexity Analysis + +##### Time Complexity: O(n log k) + +Where n is the number of elements in the array and k is the input parameter. We iterate over +all elements, and in the worst case, we both push and pop each element from the heap, which takes O(log k) time per +element. + +##### Space Complexity: O(k) + +Where k is the input parameter. The space is used by the heap to store the k largest elements. diff --git a/algorithms/heap/topklargest/__init__.py b/algorithms/heap/topklargest/__init__.py new file mode 100644 index 00000000..abc4dddd --- /dev/null +++ b/algorithms/heap/topklargest/__init__.py @@ -0,0 +1,83 @@ +from typing import List +import heapq + + +def k_largest(nums: List[int], k: int = 3) -> List[int]: + """ + Finds the k largest elements in a given list. K is defaulted to three, but can be used to tweak the k largest + elements in the array + Args: + nums(list): list of elements to check for + k(int): number of elements to check, defaulted to 3 + Returns: + list: top k largest elements + """ + # input validation to ensure we don't get unexpected results + if not nums or k <= 0: + return [] + + # Adjust k if it exceeds the length of nums + k = min(k, len(nums)) + + # create a minimum heap with the first k elements + min_heap = nums[:k] + heapq.heapify(min_heap) + + # iterate through the remaining elements + for num in nums[k:]: + # if the current number is greater than the element at the top of the heap + if num > min_heap[0]: + # Remove it and add this element + heapq.heappushpop(min_heap, num) + + # return the top k elements + return min_heap + + +def kth_largest(nums: List[int], k: int) -> int: + """ + Finds the kth largest element in a given list + Args: + nums(list): list of elements to check for + k(int): the kth largest element to return + Returns: + int: the kth largest element + """ + # input validation to ensure we don't get unexpected results + if not nums or k <= 0 or k > len(nums): + return -1 + + # create a minimum heap with the first k elements + min_heap = [] + + # iterate through the remaining elements + for num in nums: + if len(min_heap) < k: + heapq.heappush(min_heap, num) + # if the current number is greater than the element at the top of the heap + elif num > min_heap[0]: + # Remove it and add this element + heapq.heappushpop(min_heap, num) + + # return the top kth element + return min_heap[0] + + +def kth_largest_sorting(nums: List[int], k: int) -> int: + """ + Finds the kth largest element in a given list using sorting + Args: + nums(list): list of elements to check for + k(int): the kth largest element to return + Returns: + int: the kth largest element + """ + # input validation to ensure we don't get unexpected results + if not nums or k <= 0 or k > len(nums): + return -1 + + # Sort the list which incurs a time complexity cost of O(n log(n)). Space complexity is O(n) due to creating + # a new sorted list + sorted_nums = sorted(nums, reverse=True) + # Return the kth largest element + return sorted_nums[k - 1] diff --git a/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_1.png b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_1.png new file mode 100644 index 00000000..6830b70c Binary files /dev/null and b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_1.png differ diff --git a/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_10.png b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_10.png new file mode 100644 index 00000000..9192abd2 Binary files /dev/null and b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_10.png differ diff --git a/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_11.png b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_11.png new file mode 100644 index 00000000..cbb61ac4 Binary files /dev/null and b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_11.png differ diff --git a/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_2.png b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_2.png new file mode 100644 index 00000000..d2936ead Binary files /dev/null and b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_2.png differ diff --git a/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_3.png b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_3.png new file mode 100644 index 00000000..8e19e5fa Binary files /dev/null and b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_3.png differ diff --git a/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_4.png b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_4.png new file mode 100644 index 00000000..be62a010 Binary files /dev/null and b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_4.png differ diff --git a/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_5.png b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_5.png new file mode 100644 index 00000000..a5b3cbbe Binary files /dev/null and b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_5.png differ diff --git a/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_6.png b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_6.png new file mode 100644 index 00000000..ee7dad77 Binary files /dev/null and b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_6.png differ diff --git a/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_7.png b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_7.png new file mode 100644 index 00000000..fc1d95df Binary files /dev/null and b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_7.png differ diff --git a/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_8.png b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_8.png new file mode 100644 index 00000000..9c027810 Binary files /dev/null and b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_8.png differ diff --git a/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_9.png b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_9.png new file mode 100644 index 00000000..b44612c9 Binary files /dev/null and b/algorithms/heap/topklargest/images/solutions/kth_largest_element_in_array_solution_9.png differ diff --git a/algorithms/heap/topklargest/images/solutions/top_k_largest_element_in_array_solution_1.png b/algorithms/heap/topklargest/images/solutions/top_k_largest_element_in_array_solution_1.png new file mode 100644 index 00000000..08123f8a Binary files /dev/null and b/algorithms/heap/topklargest/images/solutions/top_k_largest_element_in_array_solution_1.png differ diff --git a/algorithms/heap/topklargest/images/solutions/top_k_largest_element_in_array_solution_2.png b/algorithms/heap/topklargest/images/solutions/top_k_largest_element_in_array_solution_2.png new file mode 100644 index 00000000..4fbb8695 Binary files /dev/null and b/algorithms/heap/topklargest/images/solutions/top_k_largest_element_in_array_solution_2.png differ diff --git a/algorithms/heap/topklargest/images/solutions/top_k_largest_element_in_array_solution_3.png b/algorithms/heap/topklargest/images/solutions/top_k_largest_element_in_array_solution_3.png new file mode 100644 index 00000000..f3c87caa Binary files /dev/null and b/algorithms/heap/topklargest/images/solutions/top_k_largest_element_in_array_solution_3.png differ diff --git a/algorithms/heap/topklargest/images/solutions/top_k_largest_element_in_array_solution_4.png b/algorithms/heap/topklargest/images/solutions/top_k_largest_element_in_array_solution_4.png new file mode 100644 index 00000000..13718e79 Binary files /dev/null and b/algorithms/heap/topklargest/images/solutions/top_k_largest_element_in_array_solution_4.png differ diff --git a/algorithms/heap/topklargest/images/solutions/top_k_largest_element_in_array_solution_5.png b/algorithms/heap/topklargest/images/solutions/top_k_largest_element_in_array_solution_5.png new file mode 100644 index 00000000..cbc71808 Binary files /dev/null and b/algorithms/heap/topklargest/images/solutions/top_k_largest_element_in_array_solution_5.png differ diff --git a/algorithms/heap/topklargest/test_top_k_largest_elements.py b/algorithms/heap/topklargest/test_top_k_largest_elements.py new file mode 100644 index 00000000..1bc6b48c --- /dev/null +++ b/algorithms/heap/topklargest/test_top_k_largest_elements.py @@ -0,0 +1,45 @@ +import unittest +from typing import List +from parameterized import parameterized +from algorithms.heap.topklargest import k_largest, kth_largest, kth_largest_sorting + +K_LARGEST_ELEMENTS_TEST_CASES = [ + ([9, 3, 7, 1, -2, 6, 8], 3, [8, 7, 9]), + ([5, 3, 2, 1, 4], 2, [5, 4]), +] + + +class TopKLargestElementsTestCase(unittest.TestCase): + @parameterized.expand(K_LARGEST_ELEMENTS_TEST_CASES) + def test_top_k_largest_elements(self, nums: List[int], k: int, expected: List[int]): + actual = k_largest(nums, k) + self.assertListEqual(sorted(expected), sorted(actual)) + + +KTH_LARGEST_ELEMENTS_TEST_CASES = [ + ([3, 2, 1, 5, 6, 4], 2, 5), + ([3, 2, 3, 1, 2, 4, 5, 5, 6], 4, 4), + ([1], 1, 1), + ([7, 10, 4, 3, 20, 15], 3, 10), + ([7, 10, 4, 3, 20, 15], 4, 7), + ([7, 10, 4, 3, 20, 15], 5, 4), + ([5, 3, 2, 1, 4], 2, 4), +] + + +class TopKthLargestElementsTestCase(unittest.TestCase): + @parameterized.expand(KTH_LARGEST_ELEMENTS_TEST_CASES) + def test_top_kth_largest_element(self, nums: List[int], k: int, expected: int): + actual = kth_largest(nums, k) + self.assertEqual(expected, actual) + + @parameterized.expand(KTH_LARGEST_ELEMENTS_TEST_CASES) + def test_top_kth_largest_element_sorting( + self, nums: List[int], k: int, expected: int + ): + actual = kth_largest_sorting(nums, k) + self.assertEqual(expected, actual) + + +if __name__ == "__main__": + unittest.main() diff --git a/puzzles/heap/total_cost_hire_k_workers/README.md b/algorithms/heap/total_cost_hire_k_workers/README.md similarity index 96% rename from puzzles/heap/total_cost_hire_k_workers/README.md rename to algorithms/heap/total_cost_hire_k_workers/README.md index 5d9d5786..a1bcd485 100644 --- a/puzzles/heap/total_cost_hire_k_workers/README.md +++ b/algorithms/heap/total_cost_hire_k_workers/README.md @@ -58,32 +58,32 @@ worker, a spot will open up for another worker to be among the first or last m c distinguish between the first m candidates and the last m candidates. That way, when we choose a worker, we know if a spot was opened in the first m candidates or the last m candidates. -![Step 1](./total_cost_hire_k_workers_step_1.png) +![Step 1](total_cost_hire_k_workers_step_1.png) To store the workers in two sections separately, we can use two priority queues, head_workers and tail_workers, where the worker with the lowest cost has the highest priority. -![Step 2](./total_cost_hire_k_workers_step_2.png) +![Step 2](total_cost_hire_k_workers_step_2.png) Throughout the process, after we hire a worker from a section, we need to add an additional candidate to this section. Therefore, we need two pointers, next_head and next_tail, that denotes the next worker to be added to the respective queues. -![Step 3](./total_cost_hire_k_workers_step_3.png) +![Step 3](total_cost_hire_k_workers_step_3.png) Just like in this situation shown in the picture, if two workers with the same cost appear at the top of both queues, we will hire the one from head_workers, since this worker has a smaller index compared with the other one from tail_workers. Afterwards, we need to refill head_workers with the worker at next_head to ensure that it still contains the first m unselected candidates. -![Step 4](./total_cost_hire_k_workers_step_4.png) +![Step 4](total_cost_hire_k_workers_step_4.png) However, if we encounter the condition next_tail < next_head, it indicates that all the workers have been selected as candidates and there are no more workers outside the two queues. To avoid double counting, we should not add a worker to both queues or update either pointer. Therefore, we can simply move on without making any updates to the queues or pointers. -![Step 5](./total_cost_hire_k_workers_step_5.png) +![Step 5](total_cost_hire_k_workers_step_5.png) #### Algorithm diff --git a/puzzles/heap/total_cost_hire_k_workers/__init__.py b/algorithms/heap/total_cost_hire_k_workers/__init__.py similarity index 100% rename from puzzles/heap/total_cost_hire_k_workers/__init__.py rename to algorithms/heap/total_cost_hire_k_workers/__init__.py diff --git a/puzzles/heap/total_cost_hire_k_workers/test_total_cost_hire_k_workers.py b/algorithms/heap/total_cost_hire_k_workers/test_total_cost_hire_k_workers.py similarity index 100% rename from puzzles/heap/total_cost_hire_k_workers/test_total_cost_hire_k_workers.py rename to algorithms/heap/total_cost_hire_k_workers/test_total_cost_hire_k_workers.py diff --git a/puzzles/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_1.png b/algorithms/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_1.png similarity index 100% rename from puzzles/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_1.png rename to algorithms/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_1.png diff --git a/puzzles/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_2.png b/algorithms/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_2.png similarity index 100% rename from puzzles/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_2.png rename to algorithms/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_2.png diff --git a/puzzles/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_3.png b/algorithms/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_3.png similarity index 100% rename from puzzles/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_3.png rename to algorithms/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_3.png diff --git a/puzzles/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_4.png b/algorithms/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_4.png similarity index 100% rename from puzzles/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_4.png rename to algorithms/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_4.png diff --git a/puzzles/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_5.png b/algorithms/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_5.png similarity index 100% rename from puzzles/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_5.png rename to algorithms/heap/total_cost_hire_k_workers/total_cost_hire_k_workers_step_5.png diff --git a/algorithms/matrix/__init__.py b/algorithms/matrix/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/algorithms/matrix/isvalidsudoku/README.md b/algorithms/matrix/isvalidsudoku/README.md new file mode 100644 index 00000000..fbb1f73a --- /dev/null +++ b/algorithms/matrix/isvalidsudoku/README.md @@ -0,0 +1,99 @@ +# Valid Sudoku + +Given a 9 × 9 Sudoku board, determine whether it is valid. A board is considered valid if all of the following conditions +hold (considering only the filled cells): + +- Each row contains the digits 1–9 at most once. +- Each column contains the digits 1–9 at most once. +- Each of the nine 3 × 3 sub-boxes contains the digits 1–9 at most once. + +You do not need to check whether the Sudoku is solvable; only whether the current filled entries obey these rules. + +> Note:A partially filled Sudoku board can be valid even if it is not necessarily solvable. You only need to verify that +> the filled cells adhere to the given rules. + +## Constraints + +- `board.length` == 9 +- `board[i].length` == 9 +- `board[i][j]` is a digit or a `.` + +## Examples + +![Example 1](images/examples/is_valid_sudoku_example_1.png) +![Example 2](images/examples/is_valid_sudoku_example_2.png) +![Example 3](images/examples/is_valid_sudoku_example_3.png) + +## Solution + +The intuition behind this solution is simple: instead of trying to solve the Sudoku or perform any form of search or +backtracking, we treat the board as a constraint-checking problem. As we scan the board once, cell by cell, we ensure +that every filled digit obeys the Sudoku rules, which require no repetition in its row, column, or 3×3 sub-box. To do +this efficiently, we maintain three arrays of hash sets: + +- row_sets[9]: Tracks digits seen in each row. +- col_sets[9]: Tracks digits seen in each column. +- box_sets[9]: Tracks digits seen in each 3×3 sub-box. + +Each set keeps track of the digits that have already appeared in that specific region. For every filled cell, if the +digit is already in its row, column, or sub-box set, then we’ve detected a rule violation, and the board is invalid. If +we finish scanning all 81 cells without encountering duplicates, the board is valid. This transforms the problem into a +clean, single-pass constraint check, eliminating the need for any kind of search or backtracking. + +Using the intuition above, we implement the algorithm as follows: +- Initialize an empty array, `row_sets`, to track digits in each row. +- Initialize an empty array, `col_sets`, to track digits in each column. +- Initialize an empty array, `box_sets`, to track digits in each 3×3 sub-box. +- Use an outer loop to iterate through rows. + - Use an inner loop to iterate through columns. + - Retrieve the value present at the current rows and columns of the board: `cell = board[r][c].` + - If `cell` is a ., + - Skip this value + - Compute the index of the 3×3 sub-box that contains the current cell using: `(r // 3) * 3 + (c // 3)`. + - Check whether `cell` is already present in the corresponding row, column, or box set. + - If it is, return False + - If no duplicate is found, we insert `cell` into: + - `row_set[r]`, + - `col_set[c]`, + - `box_set[box_idx]`. +- If all cells are processed without conflicts, return TRUE, indicating that the given Sudoku board is valid. + +![Example 1](images/solutions/is_valid_sudoku_solution_1.png) +![Example 2](images/solutions/is_valid_sudoku_solution_2.png) +![Example 3](images/solutions/is_valid_sudoku_solution_3.png) +![Example 4](images/solutions/is_valid_sudoku_solution_4.png) +![Example 5](images/solutions/is_valid_sudoku_solution_5.png) +![Example 6](images/solutions/is_valid_sudoku_solution_6.png) +![Example 7](images/solutions/is_valid_sudoku_solution_7.png) +![Example 8](images/solutions/is_valid_sudoku_solution_8.png) +![Example 9](images/solutions/is_valid_sudoku_solution_9.png) +![Example 10](images/solutions/is_valid_sudoku_solution_10.png) +![Example 11](images/solutions/is_valid_sudoku_solution_11.png) +![Example 12](images/solutions/is_valid_sudoku_solution_12.png) + +### Complexity + +#### Time + +The time complexity of this algorithm is constant, O(1). + +Although we iterate through all 81 cells of a 9×9 Sudoku board, the board size is fixed. In each cell, we perform +constant-time operations: + +- Hash set lookups +- Hash set insertions +- Simple arithmetic for computing the box index + +As 81 operations are a fixed constant, the overall runtime is O(1) in terms of theoretical complexity. + +#### Space + +The space complexity of this algorithm is constant, O(1). This is because we create: + +- 9 row sets +- 9 column sets +- 9 box sets + +Each can contain at most 9 digits, so a constant amount of memory bounds the total storage. + +Total extra space = 27 sets * max 9 values = 243, which is a constant number. So, the space complexity is O(1). diff --git a/algorithms/matrix/isvalidsudoku/__init__.py b/algorithms/matrix/isvalidsudoku/__init__.py new file mode 100644 index 00000000..bef563a2 --- /dev/null +++ b/algorithms/matrix/isvalidsudoku/__init__.py @@ -0,0 +1,55 @@ +from typing import List, Set + + +def is_valid_sudoku(board: List[List[str]]) -> bool: + """ + Checks if a given sudoku board is a valid sudoku board. This does not check if the board is solvable. If the board + is valid, it returns True, if not returns False. The board is a 9x9 grid with 3x3 cells. Each row only contains + digits from 1-9, and each column contains digits from 1-9 repeated once. Each 3x3 cell only contains digits from 1-9 + repeated once + Args: + board(list): A 2D grid representing a sudoku board + Returns: + bool: True if the board provided is valid, False otherwise + """ + # Handles edge cases to check if the board is of length 9 + if len(board) != 9: + return False + + # Validate each row has exactly 9 columns + if any(len(row) != 9 for row in board): + return False + + number_of_rows = len(board) + number_of_columns = len(board[0]) + row_sets: List[Set[str]] = [set() for _ in range(number_of_rows)] + col_sets: List[Set[str]] = [set() for _ in range(number_of_columns)] + box_sets: List[Set[str]] = [set() for _ in range(number_of_rows)] + + for row in range(number_of_rows): + for col in range(number_of_columns): + cell = board[row][col] + # if the cell is empty, contains a '.', we don't need to check if, we can skip and continue to the next + # iteration + if cell == ".": + continue + + # Identifying a cell within a sub-box can be found using the formula: i = (r//3)*3+(c//3) where r is the row number + # and c is the column number all indexed from 0 + # The box_idx identifies the box this cell is in + box_idx = (row // 3) * 3 + (col // 3) + + # Check if we have seen the digit before in the row, column or the box + if ( + cell in row_sets[row] + or cell in col_sets[col] + or cell in box_sets[box_idx] + ): + return False + + # if not there, we add it to the row, column and sub box sets + row_sets[row].add(cell) + col_sets[col].add(cell) + box_sets[box_idx].add(cell) + + return True diff --git a/algorithms/matrix/isvalidsudoku/images/examples/is_valid_sudoku_example_1.png b/algorithms/matrix/isvalidsudoku/images/examples/is_valid_sudoku_example_1.png new file mode 100644 index 00000000..86d58623 Binary files /dev/null and b/algorithms/matrix/isvalidsudoku/images/examples/is_valid_sudoku_example_1.png differ diff --git a/algorithms/matrix/isvalidsudoku/images/examples/is_valid_sudoku_example_2.png b/algorithms/matrix/isvalidsudoku/images/examples/is_valid_sudoku_example_2.png new file mode 100644 index 00000000..8e7df8af Binary files /dev/null and b/algorithms/matrix/isvalidsudoku/images/examples/is_valid_sudoku_example_2.png differ diff --git a/algorithms/matrix/isvalidsudoku/images/examples/is_valid_sudoku_example_3.png b/algorithms/matrix/isvalidsudoku/images/examples/is_valid_sudoku_example_3.png new file mode 100644 index 00000000..37ca3904 Binary files /dev/null and b/algorithms/matrix/isvalidsudoku/images/examples/is_valid_sudoku_example_3.png differ diff --git a/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_1.png b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_1.png new file mode 100644 index 00000000..78b19283 Binary files /dev/null and b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_1.png differ diff --git a/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_10.png b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_10.png new file mode 100644 index 00000000..e7ac403d Binary files /dev/null and b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_10.png differ diff --git a/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_11.png b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_11.png new file mode 100644 index 00000000..dac9c0e1 Binary files /dev/null and b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_11.png differ diff --git a/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_12.png b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_12.png new file mode 100644 index 00000000..df90cd36 Binary files /dev/null and b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_12.png differ diff --git a/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_2.png b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_2.png new file mode 100644 index 00000000..c14feb9b Binary files /dev/null and b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_2.png differ diff --git a/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_3.png b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_3.png new file mode 100644 index 00000000..7a5fbc54 Binary files /dev/null and b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_3.png differ diff --git a/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_4.png b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_4.png new file mode 100644 index 00000000..2ca30f6d Binary files /dev/null and b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_4.png differ diff --git a/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_5.png b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_5.png new file mode 100644 index 00000000..6b3c3359 Binary files /dev/null and b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_5.png differ diff --git a/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_6.png b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_6.png new file mode 100644 index 00000000..876b2e2a Binary files /dev/null and b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_6.png differ diff --git a/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_7.png b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_7.png new file mode 100644 index 00000000..fe9cbc24 Binary files /dev/null and b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_7.png differ diff --git a/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_8.png b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_8.png new file mode 100644 index 00000000..24de84ce Binary files /dev/null and b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_8.png differ diff --git a/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_9.png b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_9.png new file mode 100644 index 00000000..43f4c4e6 Binary files /dev/null and b/algorithms/matrix/isvalidsudoku/images/solutions/is_valid_sudoku_solution_9.png differ diff --git a/algorithms/matrix/isvalidsudoku/test_is_valid_sudoku.py b/algorithms/matrix/isvalidsudoku/test_is_valid_sudoku.py new file mode 100644 index 00000000..73664b23 --- /dev/null +++ b/algorithms/matrix/isvalidsudoku/test_is_valid_sudoku.py @@ -0,0 +1,88 @@ +import unittest +from typing import List +from parameterized import parameterized +from algorithms.matrix.isvalidsudoku import is_valid_sudoku + +IS_VALID_SUDOKU_TEST_CASES = [ + ( + [ + [".", ".", ".", ".", ".", ".", ".", "7", "."], + ["2", "7", "5", ".", ".", ".", "3", "1", "4"], + [".", ".", ".", ".", "2", "7", ".", "5", "."], + ["9", "8", ".", ".", ".", ".", ".", "3", "1"], + [".", "3", "1", "8", ".", "4", ".", ".", "."], + [".", ".", ".", "1", ".", ".", "8", ".", "5"], + ["7", ".", "6", "2", ".", ".", "1", "8", "."], + [".", "9", ".", "7", ".", ".", ".", ".", "."], + ["4", "1", ".", ".", ".", "5", ".", ".", "7"], + ], + True, + ), + ( + [ + ["5", "3", "3", "6", "7", "8", "9", "1", "2"], + ["6", "7", "2", "1", "9", "5", "3", "4", "8"], + ["1", "9", "8", "3", "4", "2", "5", "6", "7"], + ["8", "5", "9", "7", "6", "1", "4", "2", "3"], + ["4", "2", "6", "8", "5", "3", "7", "9", "1"], + ["7", "1", "3", "9", "2", "4", "8", "5", "6"], + ["9", "6", "1", "5", "3", "7", "2", "8", "4"], + ["2", "8", "7", "4", "1", "9", "6", "3", "5"], + ["3", "4", "5", "2", "8", "6", "1", "7", "9"], + ], + False, + ), + ( + [ + ["6", "4", "5", "9", "8", "2", "1", "3", "7"], + ["7", "2", "8", "3", "1", "6", "5", "9", "4"], + ["3", "9", "1", "5", "4", "7", "6", "8", "2"], + ["9", "8", "7", "1", "5", "3", "4", "2", "6"], + ["4", "1", "6", "2", "7", "9", "8", "5", "3"], + ["5", "3", "2", "8", "6", "4", "7", "1", "9"], + ["8", "7", "3", "6", "9", "5", "2", "4", "1"], + ["2", "5", "4", "7", "3", "1", "9", "6", "8"], + ["1", "6", "9", "4", "2", "8", "3", "7", "5"], + ], + True, + ), + ( + [ + ["6", "3", "9", "4", "2", "5", "7", "1", "8"], + ["6", "4", "8", "1", "3", "7", "9", "6", "5"], + ["5", "7", "1", "9", "6", "8", "3", "4", "2"], + ["1", "6", "2", "7", "5", "4", "8", "3", "9"], + ["4", "8", "3", "6", "9", "2", "5", "7", "1"], + ["9", "5", "7", "3", "8", "1", "6", "2", "4"], + ["8", "2", "6", "5", "4", "3", "1", "9", "7"], + ["3", "1", "5", "2", "7", "9", "4", "8", "6"], + ["7", "9", "4", "8", "1", "6", "2", "5", "3"], + ], + False, + ), + ( + [ + ["5", "3", ".", ".", "7", ".", ".", ".", "."], + ["6", ".", ".", "1", "9", "5", ".", ".", "."], + [".", "9", "8", ".", ".", ".", ".", "6", "."], + ["8", ".", ".", ".", "6", ".", ".", ".", "3"], + ["4", ".", ".", "8", ".", "3", ".", ".", "1"], + ["7", ".", ".", ".", "2", ".", ".", ".", "6"], + [".", "6", ".", ".", ".", ".", "2", "8", "."], + [".", ".", ".", "4", "1", "9", ".", ".", "5"], + [".", ".", ".", ".", "8", ".", ".", "7", "9"], + ], + True, + ), +] + + +class IsValidSudokuTestCase(unittest.TestCase): + @parameterized.expand(IS_VALID_SUDOKU_TEST_CASES) + def test_is_valid_sudoku(self, board: List[List[str]], expected: bool): + actual = is_valid_sudoku(board) + self.assertEqual(expected, actual) + + +if __name__ == "__main__": + unittest.main()