diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index a05b67a2..bdd3ea4e 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -6,8 +6,8 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/cache@v2 + - uses: actions/checkout@v5 + - uses: actions/cache@v4 with: path: | ~/.cache/pre-commit diff --git a/DIRECTORY.md b/DIRECTORY.md index 495f67b4..d612b6d8 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -75,6 +75,9 @@ * [Test Find Duplicate](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/fast_and_slow/find_duplicate/test_find_duplicate.py) * Happy Number * [Test Happy Number](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/fast_and_slow/happy_number/test_happy_number.py) + * Graphs + * Course Schedule + * [Test Course Schedule](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/graphs/course_schedule/test_course_schedule.py) * Greedy * Min Arrows * [Test Find Min Arrows](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/greedy/min_arrows/test_find_min_arrows.py) diff --git a/README.md b/README.md index 45c510c0..f45b962f 100755 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ ## Python Snippets [![Build Status](https://travis-ci.org/BrianLusina/Python_Snippets.svg?branch=master)](https://travis-ci.org/BrianLusina/Python_Snippets) +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/11cfc8e125c54bdb833fe19ed9ddad72)](https://app.codacy.com/gh/BrianLusina/Python_Snippets/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) Repository for some of my simple [Python](https://www.python.org/ "Python") functions and snippets. Each directory and/or python package has a readme for more information about the Python program diff --git a/algorithms/arrays/intersection/intersection_two.py b/algorithms/arrays/intersection/intersection_two.py index ad22c60b..6ef0ce3d 100644 --- a/algorithms/arrays/intersection/intersection_two.py +++ b/algorithms/arrays/intersection/intersection_two.py @@ -3,7 +3,9 @@ T = TypeVar("T") -def intersect(list_one: List[T], list_two: List[T], include_duplicates: bool = True) -> List[T]: +def intersect( + list_one: List[T], list_two: List[T], include_duplicates: bool = True +) -> List[T]: """ Given two arrays, find their intersection. This assumes that the lists are not sorted. First sorting takes place on both lists which will incur a cost of O(nlog(n)) + O(mlog(m)) depending on the algorithm used. Time will also @@ -35,7 +37,10 @@ def intersect(list_one: List[T], list_two: List[T], include_duplicates: bool = T if include_duplicates: result.append(first_element) else: - if pointer_one == 0 or first_element != sorted_list_one[pointer_one - 1]: + if ( + pointer_one == 0 + or first_element != sorted_list_one[pointer_one - 1] + ): result.append(first_element) pointer_one += 1 pointer_two += 1 diff --git a/algorithms/arrays/non_constructible_change/test_non_constructible_change.py b/algorithms/arrays/non_constructible_change/test_non_constructible_change.py index 0963b12c..06a08be9 100644 --- a/algorithms/arrays/non_constructible_change/test_non_constructible_change.py +++ b/algorithms/arrays/non_constructible_change/test_non_constructible_change.py @@ -95,11 +95,12 @@ def test_13(self): self.assertEqual(actual, expected) def test_input_not_mutated(self): - """should not mutate the input coins list""" - coins = [5, 7, 1, 1, 2, 3, 22] - snapshot = coins[:] - _ = non_constructible_change(coins) - self.assertEqual(coins, snapshot) + """should not mutate the input coins list""" + coins = [5, 7, 1, 1, 2, 3, 22] + snapshot = coins[:] + _ = non_constructible_change(coins) + self.assertEqual(coins, snapshot) + -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/algorithms/arrays/optimal_task_assignment/test_optimal_task_assignment.py b/algorithms/arrays/optimal_task_assignment/test_optimal_task_assignment.py index c3a3a2d3..50bb187c 100644 --- a/algorithms/arrays/optimal_task_assignment/test_optimal_task_assignment.py +++ b/algorithms/arrays/optimal_task_assignment/test_optimal_task_assignment.py @@ -11,5 +11,5 @@ def test_1(self): self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/algorithms/arrays/sorted_squared_array/__init__.py b/algorithms/arrays/sorted_squared_array/__init__.py index 454a5b89..1639cbbf 100644 --- a/algorithms/arrays/sorted_squared_array/__init__.py +++ b/algorithms/arrays/sorted_squared_array/__init__.py @@ -20,7 +20,7 @@ def sorted_squared_array(array: List[int]) -> List[int]: left, right = 0, n - 1 # file result array from right to left (largest to smallest squares - for i in range(n-1, -1, -1): + for i in range(n - 1, -1, -1): left_abs = abs(array[left]) right_abs = abs(array[right]) @@ -56,7 +56,7 @@ def sorted_squared_array_2(array: List[int]) -> List[int]: left, right = 0, n - 1 # file result array from right to left (largest to smallest squares - for i in range(n-1, -1, -1): + for i in range(n - 1, -1, -1): left_square = array[left] ** 2 right_square = array[right] ** 2 diff --git a/algorithms/arrays/sorted_squared_array/test_sorted_squared_array.py b/algorithms/arrays/sorted_squared_array/test_sorted_squared_array.py index 5e2efab7..ee1e12a8 100644 --- a/algorithms/arrays/sorted_squared_array/test_sorted_squared_array.py +++ b/algorithms/arrays/sorted_squared_array/test_sorted_squared_array.py @@ -19,8 +19,8 @@ def test_2(self): def test_3(self): """for an input of [-7,-3,2,3,11] it should return [4,9,9,49,121]""" - input_array = [-7,-3,2,3,11] - expected = [4,9,9,49,121] + input_array = [-7, -3, 2, 3, 11] + expected = [4, 9, 9, 49, 121] actual = sorted_squared_array(input_array) self.assertEqual(expected, actual) @@ -42,11 +42,11 @@ def test_2(self): def test_3(self): """for an input of [-7,-3,2,3,11] it should return [4,9,9,49,121]""" - input_array = [-7,-3,2,3,11] - expected = [4,9,9,49,121] + input_array = [-7, -3, 2, 3, 11] + expected = [4, 9, 9, 49, 121] actual = sorted_squared_array_2(input_array) self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/algorithms/arrays/subsequence/__init__.py b/algorithms/arrays/subsequence/__init__.py index bc23c8be..fa0267f5 100644 --- a/algorithms/arrays/subsequence/__init__.py +++ b/algorithms/arrays/subsequence/__init__.py @@ -37,6 +37,7 @@ def is_valid_subsequence(array: List[int], sequence: List[int]) -> bool: return False + def is_valid_subsequence_v2(array: List[int], sequence: List[int]) -> bool: """ Returns true if a sequence is a subsequence of the provided array diff --git a/algorithms/arrays/subsequence/test_is_valid_subsequence.py b/algorithms/arrays/subsequence/test_is_valid_subsequence.py index dc6728c9..3d741b76 100644 --- a/algorithms/arrays/subsequence/test_is_valid_subsequence.py +++ b/algorithms/arrays/subsequence/test_is_valid_subsequence.py @@ -12,32 +12,33 @@ def test_1(self): def test_2(self): """should return True for array = [5, 1, 22, 25, 6, -1, 8, 10], sequence = [5, 1, 22, 6, -1, 8, 10]""" - array = [5, 1, 22, 25, 6, -1, 8, 10] + array = [5, 1, 22, 25, 6, -1, 8, 10] sequence = [5, 1, 22, 6, -1, 8, 10] actual = is_valid_subsequence(array, sequence) self.assertTrue(actual) def test_3(self): """should return False for array = [5, 1, 22, 25, 6, -1, 8, 10], sequence = [5, 6, 1, 10, 22, 8, -1, 25]""" - array = [5, 1, 22, 25, 6, -1, 8, 10] + array = [5, 1, 22, 25, 6, -1, 8, 10] sequence = [5, 6, 1, 10, 22, 8, -1, 25] actual = is_valid_subsequence(array, sequence) self.assertFalse(actual) def test_4(self): """should return True for array = [1,2,3,4], sequence = [1,3,4]""" - array = [1,2,3,4] - sequence = [1,3,4] + array = [1, 2, 3, 4] + sequence = [1, 3, 4] actual = is_valid_subsequence(array, sequence) self.assertTrue(actual) def test_5(self): """should return True for array = [1,2,3,4], sequence = [2,4]""" - array = [1,2,3,4] - sequence = [2,4] + array = [1, 2, 3, 4] + sequence = [2, 4] actual = is_valid_subsequence(array, sequence) self.assertTrue(actual) + class IsValidSubsequenceV2TestCase(unittest.TestCase): def test_1(self): """array = [5, 1, 22, 25, 6, -1, 8, 10], sequence = [1, 6, -1, 10]""" @@ -48,32 +49,32 @@ def test_1(self): def test_2(self): """should return True for array = [5, 1, 22, 25, 6, -1, 8, 10], sequence = [5, 1, 22, 6, -1, 8, 10]""" - array = [5, 1, 22, 25, 6, -1, 8, 10] + array = [5, 1, 22, 25, 6, -1, 8, 10] sequence = [5, 1, 22, 6, -1, 8, 10] actual = is_valid_subsequence_v2(array, sequence) self.assertTrue(actual) def test_3(self): """should return False for array = [5, 1, 22, 25, 6, -1, 8, 10], sequence = [5, 6, 1, 10, 22, 8, -1, 25]""" - array = [5, 1, 22, 25, 6, -1, 8, 10] + array = [5, 1, 22, 25, 6, -1, 8, 10] sequence = [5, 6, 1, 10, 22, 8, -1, 25] actual = is_valid_subsequence_v2(array, sequence) self.assertFalse(actual) def test_4(self): """should return True for array = [1,2,3,4], sequence = [1,3,4]""" - array = [1,2,3,4] - sequence = [1,3,4] + array = [1, 2, 3, 4] + sequence = [1, 3, 4] actual = is_valid_subsequence_v2(array, sequence) self.assertTrue(actual) def test_5(self): """should return True for array = [1,2,3,4], sequence = [2,4]""" - array = [1,2,3,4] - sequence = [2,4] + array = [1, 2, 3, 4] + sequence = [2, 4] actual = is_valid_subsequence_v2(array, sequence) self.assertTrue(actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/algorithms/fast_and_slow/circular_array_loop/test_circular_array_loop.py b/algorithms/fast_and_slow/circular_array_loop/test_circular_array_loop.py index a5fba49a..79cc4d39 100644 --- a/algorithms/fast_and_slow/circular_array_loop/test_circular_array_loop.py +++ b/algorithms/fast_and_slow/circular_array_loop/test_circular_array_loop.py @@ -5,7 +5,7 @@ class CircularArrayLoopTestCase(unittest.TestCase): def test_1(self): """should return True for [3,1,2]""" - nums = [3,1,2] + nums = [3, 1, 2] actual = circular_array_loop(nums) self.assertTrue(actual) @@ -17,46 +17,46 @@ def test_2(self): def test_3(self): """should return False for [2,1,-1,-2]""" - nums = [2,1,-1,-2] + nums = [2, 1, -1, -2] actual = circular_array_loop(nums) self.assertFalse(actual) def test_4(self): """should return True for [3,-3,1,1]""" - nums = [3,-3,1,1] + nums = [3, -3, 1, 1] actual = circular_array_loop(nums) self.assertTrue(actual) def test_5(self): """should return True for [1,3,-2,-4,1]""" - nums = [1,3,-2,-4,1] + nums = [1, 3, -2, -4, 1] actual = circular_array_loop(nums) self.assertTrue(actual) def test_6(self): """should return True for [2,1,-1,-2]""" - nums = [2,1,-1,-2] + nums = [2, 1, -1, -2] actual = circular_array_loop(nums) self.assertFalse(actual) def test_7(self): """should return True for [5,4,-2,-1,3]""" - nums = [5,4,-2,-1,3] + nums = [5, 4, -2, -1, 3] actual = circular_array_loop(nums) self.assertFalse(actual) def test_8(self): """should return True for [1,2,-3,3,4,7,1]""" - nums = [1,2,-3,3,4,7,1] + nums = [1, 2, -3, 3, 4, 7, 1] actual = circular_array_loop(nums) self.assertTrue(actual) def test_9(self): """should return True for [3,3,1,-1,2]""" - nums = [3,3,1,-1,2] + nums = [3, 3, 1, -1, 2] actual = circular_array_loop(nums) self.assertTrue(actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/algorithms/fast_and_slow/find_duplicate/test_find_duplicate.py b/algorithms/fast_and_slow/find_duplicate/test_find_duplicate.py index 08a39ce0..0e8b7e9f 100644 --- a/algorithms/fast_and_slow/find_duplicate/test_find_duplicate.py +++ b/algorithms/fast_and_slow/find_duplicate/test_find_duplicate.py @@ -124,7 +124,7 @@ def test_10(self): def test_11(self): """nums = [1,3,4,2,2] should return 2""" - nums = [1,3,4,2,2] + nums = [1, 3, 4, 2, 2] expected = 2 actual = find_duplicate_floyd_algo(nums) @@ -133,7 +133,7 @@ def test_11(self): def test_12(self): """nums = [1,3,6,2,7,3,5,4] should return 3""" - nums = [1,3,6,2,7,3,5,4] + nums = [1, 3, 6, 2, 7, 3, 5, 4] expected = 3 actual = find_duplicate_floyd_algo(nums) @@ -142,7 +142,7 @@ def test_12(self): def test_13(self): """nums = [1,2,2] should return 2""" - nums = [1,2,2] + nums = [1, 2, 2] expected = 2 actual = find_duplicate_floyd_algo(nums) diff --git a/algorithms/fast_and_slow/happy_number/__init__.py b/algorithms/fast_and_slow/happy_number/__init__.py index ba4c0a3b..51f80db1 100644 --- a/algorithms/fast_and_slow/happy_number/__init__.py +++ b/algorithms/fast_and_slow/happy_number/__init__.py @@ -35,6 +35,7 @@ def get_next(number: int) -> int: return n == 1 + def is_happy_number_2(n: int) -> bool: """ Checks if an unsigned integer is a happy number diff --git a/algorithms/fast_and_slow/happy_number/test_happy_number.py b/algorithms/fast_and_slow/happy_number/test_happy_number.py index 38a5fb20..2cdc8bb6 100644 --- a/algorithms/fast_and_slow/happy_number/test_happy_number.py +++ b/algorithms/fast_and_slow/happy_number/test_happy_number.py @@ -57,6 +57,7 @@ def test_9(self): actual = is_happy_number(number) self.assertFalse(actual) + class HappyNumberTestCase2(unittest.TestCase): def test_1(self): """should return true for 23""" @@ -113,5 +114,5 @@ def test_9(self): self.assertFalse(actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/algorithms/graphs/course_schedule/README.md b/algorithms/graphs/course_schedule/README.md index 7807254d..aff5c9b8 100644 --- a/algorithms/graphs/course_schedule/README.md +++ b/algorithms/graphs/course_schedule/README.md @@ -11,29 +11,55 @@ should take to finish all courses. If there are many valid answers, return any of them. If it is impossible to finish all courses, return an empty array. Example 1: - +```text Input: numCourses = 2, prerequisites = [[1,0]] Output: [0,1] Explanation: There are a total of 2 courses to take. To take course 1 you should have finished course 0. So the correct -course order is [0,1]. Example 2: +course order is [0,1]. +``` +Example 2: +```text Input: numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]] Output: [0,2,1,3] Explanation: There are a total of 4 courses to take. To take course 3 you should have finished both courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. So one correct course order is [0,1,2,3]. Another -correct ordering is [0,2,1,3]. Example 3: +correct ordering is [0,2,1,3]. +``` +Example 3: +```text Input: numCourses = 1, prerequisites = [] Output: [0] +``` + +Example 4: +```text +Input: numCourses = 3, prerequisites = [[1,0],[2,1]] +Output: [0,1,2] +``` + +Example 5: +```text +Input: numCourses = 3, prerequisites = [[1,0],[2,1],[1,2]] +Output: [] +``` + +Example 6: +```text +Input: numCourses = 5, prerequisites = [[1,0],[2,1],[4,3]] +Output: [0,1,2,3,4] +``` Constraints: -1 <= numCourses <= 2000 0 <= prerequisites.length <= numCourses * (numCourses - 1) -prerequisites[i].length == 2 0 <= ai, bi < numCourses ai != bi All the pairs [ai, bi] are distinct. +- 1 <= numCourses <= 2000 +- 0 <= prerequisites.length <= numCourses * (numCourses - 1) +- prerequisites[i].length == 2 0 <= ai, bi < numCourses ai != bi All the pairs [ai, bi] are distinct. --- -# Solution Breakdown - Using Depth First Search +## Solution 1 Breakdown (Using Depth First Search) Suppose we are at a node in our graph during the depth first traversal. Let's call this node A. @@ -56,7 +82,7 @@ Initialize a stack S that will contain the topologically sorted order of the cou adjacency list using the edge pairs given in the input. An important thing to note about the input for the problem is that a pair such as [a, b] represents that the course b needs to be taken in order to do the course a. This implies an edge of the form b ➔ a. Please take note of this when implementing the algorithm. For each of the nodes in our graph, we -will run a depth first search in case that node was not already visited in some other node's DFS traversal. Suppose we +will run a depth-first search in case that node was not already visited in some other node's DFS traversal. Suppose we are executing the depth first search for a node N. We will recursively traverse all of the neighbors of node N which have not been processed before. Once the processing of all the neighbors is done, we will add the node N to the stack. We are making use of a stack to simulate the ordering we need. When we add the node N to the stack, all the nodes that @@ -65,10 +91,14 @@ processed, we will simply return the nodes as they are present in the stack from ## Complexity Analysis -Time Complexity: O(V+E) where V represents the number of vertices and E represents the number of edges. -Essentially we iterate through each node and each vertex in the graph once and only once. +### Time Complexity + +O(V+E) where V represents the number of vertices and E represents the number of edges. Essentially we iterate through +each node and each vertex in the graph once and only once. -Space Complexity: O(V+E). +### Space Complexity: + +O(V+E). We use the adjacency list to represent our graph initially. The space occupied is defined by the number of edges because for each node as the key, we have all its adjacent nodes in the form of a list as the value. Hence, O(E) @@ -76,4 +106,42 @@ for each node as the key, we have all its adjacent nodes in the form of a list a Additionally, we apply recursion in our algorithm, which in worst case will incur O(E) extra space in the function call stack. -To sum up, the overall space complexity is O(V+E). \ No newline at end of file +To sum up, the overall space complexity is O(V+E). + +--- + +## Solution 2 Breakdown + +Initialize the hash map with the vertices and their children. We’ll use another hash map to keep track of the number of +in-degrees of each vertex. Then we’ll find the source vertex (with 0 in-degree) and increment the counter. Retrieve the +source node’s children and add them to the queue. Decrement the in-degrees of the retrieved children. We’ll check +whether the in-degree of the child vertex becomes equal to zero, and we increment the counter. Repeat the process until +the queue is empty. + +> Note: The in-degree is the number of edges coming into a vertex in a directed graph. + +The primary purpose of finding a vertex with 0 in-degree is to find a course with a pre-requisite count of 0. When we +take a course, say a (that is the pre-requisite of another course, say b), we’ll decrement the in-degree of b by 1, and +if the in-degree count becomes 0, we can say that the b’s pre-requisites have been completed. + +The images below illustrate the algorithm above, where num_courses = 6: + +![Solution_2_slide_1](./images/solution_2_slide_1.png) +![Solution_2_slide_2](./images/solution_2_slide_2.png) +![Solution_2_slide_3](./images/solution_2_slide_3.png) +![Solution_2_slide_4](./images/solution_2_slide_4.png) +![Solution_2_slide_5](./images/solution_2_slide_5.png) +![Solution_2_slide_6](./images/solution_2_slide_6.png) +![Solution_2_slide_7](./images/solution_2_slide_7.png) +![Solution_2_slide_8](./images/solution_2_slide_8.png) +![Solution_2_slide_9](./images/solution_2_slide_9.png) + +### Time Complexity + +In the algorithm above, each course will become a source only once, and each edge will be accessed and removed once. +Therefore, the above algorithm’s time complexity will be O(V+E), where V is the total number of vertices and E is the +total number of edges in the graph. + +### Space Complexity + +The space complexity will be O(V+E) because we’re storing all of the edges for each vertex in an adjacency list. diff --git a/algorithms/graphs/course_schedule/__init__.py b/algorithms/graphs/course_schedule/__init__.py index 3ed1597a..59a8dc04 100644 --- a/algorithms/graphs/course_schedule/__init__.py +++ b/algorithms/graphs/course_schedule/__init__.py @@ -1,5 +1,5 @@ -from collections import defaultdict -from typing import List +from collections import defaultdict, deque +from typing import List, Dict, Deque WHITE = 1 GRAY = 2 @@ -7,35 +7,118 @@ def find_order(num_courses: int, prerequisites: List[List[int]]) -> List[int]: + """ + This function finds the topological sorted order of the courses given the prerequisites. + + Args: + num_courses (int): The total number of courses. + prerequisites (List[List[int]]): A list of tuples where each tuple contains the source and destination of the prerequisite. + + Returns: + List[int]: A list of the courses in the topological sorted order. If there is no valid order, return an empty list. + + """ adjacency_list = defaultdict(list) + # Populate the adjacency list with the prerequisites for destination, source in prerequisites: adjacency_list[source].append(destination) + topological_sorted_order = [] is_possible = True + # Use a dictionary to keep track of the color of each node color = {k: WHITE for k in range(num_courses)} def dfs(node): + """ + This function performs a depth-first search on the graph. + + Args: + node (int): The current node being visited. + + Returns: + None + + """ nonlocal is_possible + # If there is no valid order, return immediately if not is_possible: return + # Mark the current node as gray color[node] = GRAY + # If the current node has any neighbours, visit them if node in adjacency_list: for neighbour in adjacency_list[node]: + # If the neighbour is white, visit it if color[neighbour] == WHITE: dfs(neighbour) + # If the neighbour is gray, there is no valid order elif color[neighbour] == GRAY: is_possible = False + # Mark the current node as black color[node] = BLACK topological_sorted_order.append(node) + # Visit all the nodes for vertex in range(num_courses): if color[vertex] == WHITE: dfs(vertex) + # If there is no valid order, return an empty list return topological_sorted_order[::-1] if is_possible else [] + + +def can_finish(num_courses: int, prerequisites: List[List[int]]) -> bool: + """ + Determines if there is a valid order of courses such that + all prerequisites are satisfied. + + Args: + num_courses (int): The total number of courses. + prerequisites (List[List[int]]): A list of tuples where each tuple contains the source and destination of the prerequisite. + + Returns: + bool: True if there is a valid order, False otherwise. + """ + counter: int = 0 + if num_courses <= 0: + return True + + # Initialize the in-degree of all nodes to 0 + in_degree: Dict[int, int] = {i: 0 for i in range(num_courses)} + # Initialize an adjacency list to store the graph + graph: Dict[int, List[int]] = {i: [] for i in range(num_courses)} + + # Populate the adjacency list and the in-degree of all nodes + for child, parent in prerequisites: + if parent in graph: + graph[parent].append(child) + else: + graph[parent] = [child] + if child in in_degree: + in_degree[child] += 1 + else: + in_degree[child] = 1 + + # Initialize a queue to store all nodes with an in-degree of 0 + sources: Deque[int] = deque() + for key in in_degree: + if in_degree[key] == 0: + sources.append(key) + + # Perform a BFS traversal of the graph + while sources: + course: int = sources.popleft() + counter += 1 + for child in graph[course]: + in_degree[child] -= 1 + if in_degree[child] == 0: + sources.append(child) + + # If all nodes have been visited, return True + return counter == num_courses diff --git a/algorithms/graphs/course_schedule/images/solution_2_slide_1.png b/algorithms/graphs/course_schedule/images/solution_2_slide_1.png new file mode 100644 index 00000000..60d94dde Binary files /dev/null and b/algorithms/graphs/course_schedule/images/solution_2_slide_1.png differ diff --git a/algorithms/graphs/course_schedule/images/solution_2_slide_2.png b/algorithms/graphs/course_schedule/images/solution_2_slide_2.png new file mode 100644 index 00000000..a2b53ed1 Binary files /dev/null and b/algorithms/graphs/course_schedule/images/solution_2_slide_2.png differ diff --git a/algorithms/graphs/course_schedule/images/solution_2_slide_3.png b/algorithms/graphs/course_schedule/images/solution_2_slide_3.png new file mode 100644 index 00000000..c63051c8 Binary files /dev/null and b/algorithms/graphs/course_schedule/images/solution_2_slide_3.png differ diff --git a/algorithms/graphs/course_schedule/images/solution_2_slide_4.png b/algorithms/graphs/course_schedule/images/solution_2_slide_4.png new file mode 100644 index 00000000..9c628b8e Binary files /dev/null and b/algorithms/graphs/course_schedule/images/solution_2_slide_4.png differ diff --git a/algorithms/graphs/course_schedule/images/solution_2_slide_5.png b/algorithms/graphs/course_schedule/images/solution_2_slide_5.png new file mode 100644 index 00000000..6debd3f4 Binary files /dev/null and b/algorithms/graphs/course_schedule/images/solution_2_slide_5.png differ diff --git a/algorithms/graphs/course_schedule/images/solution_2_slide_6.png b/algorithms/graphs/course_schedule/images/solution_2_slide_6.png new file mode 100644 index 00000000..0a7dc969 Binary files /dev/null and b/algorithms/graphs/course_schedule/images/solution_2_slide_6.png differ diff --git a/algorithms/graphs/course_schedule/images/solution_2_slide_7.png b/algorithms/graphs/course_schedule/images/solution_2_slide_7.png new file mode 100644 index 00000000..2e3b1938 Binary files /dev/null and b/algorithms/graphs/course_schedule/images/solution_2_slide_7.png differ diff --git a/algorithms/graphs/course_schedule/images/solution_2_slide_8.png b/algorithms/graphs/course_schedule/images/solution_2_slide_8.png new file mode 100644 index 00000000..8faf9742 Binary files /dev/null and b/algorithms/graphs/course_schedule/images/solution_2_slide_8.png differ diff --git a/algorithms/graphs/course_schedule/images/solution_2_slide_9.png b/algorithms/graphs/course_schedule/images/solution_2_slide_9.png new file mode 100644 index 00000000..2bb4e9dd Binary files /dev/null and b/algorithms/graphs/course_schedule/images/solution_2_slide_9.png differ diff --git a/algorithms/graphs/course_schedule/test_course_schedule.py b/algorithms/graphs/course_schedule/test_course_schedule.py new file mode 100644 index 00000000..2563a499 --- /dev/null +++ b/algorithms/graphs/course_schedule/test_course_schedule.py @@ -0,0 +1,88 @@ +import unittest +from . import find_order, can_finish + + +class FindOrderTestCase(unittest.TestCase): + def test_1(self): + num_courses = 2 + prerequisites = [[1, 0]] + expected = [0, 1] + actual = find_order(num_courses=num_courses, prerequisites=prerequisites) + self.assertEqual(expected, actual) + + def test_2(self): + num_courses = 4 + prerequisites = [[1, 0], [2, 0], [3, 1], [3, 2]] + expected = [0, 2, 1, 3] + actual = find_order(num_courses=num_courses, prerequisites=prerequisites) + self.assertEqual(expected, actual) + + def test_3(self): + num_courses = 1 + prerequisites = [] + expected = [0] + actual = find_order(num_courses=num_courses, prerequisites=prerequisites) + self.assertEqual(expected, actual) + + def test_4(self): + num_courses = 3 + prerequisites = [[1, 0], [2, 1]] + expected = [0, 1, 2] + actual = find_order(num_courses=num_courses, prerequisites=prerequisites) + self.assertEqual(expected, actual) + + def test_5(self): + num_courses = 3 + prerequisites = [[1, 0], [2, 1], [1, 2]] + expected = [] + actual = find_order(num_courses=num_courses, prerequisites=prerequisites) + self.assertEqual(expected, actual) + + def test_6(self): + num_courses = 3 + prerequisites = [[1, 0], [2, 1], [4, 3]] + expected = [0, 1, 2] # or [0,1,2,3,4] + actual = find_order(num_courses=num_courses, prerequisites=prerequisites) + self.assertEqual(expected, actual) + + +class CanFinishTestCases(unittest.TestCase): + def test_1(self): + num_courses = 2 + prerequisites = [[1, 0]] + actual = can_finish(num_courses=num_courses, prerequisites=prerequisites) + self.assertTrue(actual) + + def test_2(self): + num_courses = 4 + prerequisites = [[1, 0], [2, 0], [3, 1], [3, 2]] + actual = can_finish(num_courses=num_courses, prerequisites=prerequisites) + self.assertTrue(actual) + + def test_3(self): + num_courses = 1 + prerequisites = [] + actual = can_finish(num_courses=num_courses, prerequisites=prerequisites) + self.assertTrue(actual) + + def test_4(self): + num_courses = 3 + prerequisites = [[1, 0], [2, 1]] + actual = can_finish(num_courses=num_courses, prerequisites=prerequisites) + self.assertTrue(actual) + + def test_5(self): + num_courses = 3 + prerequisites = [[1, 0], [2, 1], [1, 2]] + actual = can_finish(num_courses=num_courses, prerequisites=prerequisites) + self.assertFalse(actual) + + def test_6(self): + num_courses = 3 + prerequisites = [[1, 0], [2, 1], [4, 3]] + actual = can_finish(num_courses=num_courses, prerequisites=prerequisites) + self.assertTrue(actual) + + +if __name__ == "__main__": + unittest.main() diff --git a/algorithms/josephus_circle/test_josephus_circle.py b/algorithms/josephus_circle/test_josephus_circle.py index 301206ce..63a516b0 100644 --- a/algorithms/josephus_circle/test_josephus_circle.py +++ b/algorithms/josephus_circle/test_josephus_circle.py @@ -60,5 +60,5 @@ def test_5(self): self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/algorithms/sliding_window/repeated_dna_sequences/__init__.py b/algorithms/sliding_window/repeated_dna_sequences/__init__.py index a1e3d4f3..a870b6b8 100644 --- a/algorithms/sliding_window/repeated_dna_sequences/__init__.py +++ b/algorithms/sliding_window/repeated_dna_sequences/__init__.py @@ -19,7 +19,7 @@ def find_repeated_dna_sequences_naive(dna_sequence: str) -> List[str]: result_set = set() seen = set() for idx in range(len(dna_sequence)): - subsequence = dna_sequence[idx:idx+10] + subsequence = dna_sequence[idx : idx + 10] if len(subsequence) < 10: continue if subsequence in seen: @@ -29,6 +29,7 @@ def find_repeated_dna_sequences_naive(dna_sequence: str) -> List[str]: return list(result_set) + def find_repeated_dna_sequences(dna_sequence: str) -> List[str]: """ Finds all repeated DNA sequences in a given string. @@ -43,18 +44,23 @@ def find_repeated_dna_sequences(dna_sequence: str) -> List[str]: """ to_int = {"A": 0, "C": 1, "G": 2, "T": 3} - # Validate input contains only valid DNA bases + # Validate input contains only valid DNA bases if not all(c in to_int for c in dna_sequence): - raise ValueError(f"DNA sequence contains invalid characters. Only A, C, G, T are allowed.") + raise ValueError( + "DNA sequence contains invalid characters. Only A, C, G, T are allowed." + ) encoded_sequence = [to_int[c] for c in dna_sequence] - dna_sequence_substr_length, dna_sequence_length = 10, len(dna_sequence) # Length of DNA sequence to check + dna_sequence_substr_length, dna_sequence_length = ( + 10, + len(dna_sequence), + ) # Length of DNA sequence to check if dna_sequence_length <= dna_sequence_substr_length: return [] - base_a_encoding = 4 # Base-4 encoding + base_a_encoding = 4 # Base-4 encoding rolling_hash_value = 0 seen_hashes, output = set(), set() a_k = 1 # Stores a^k for hash updates @@ -62,21 +68,24 @@ def find_repeated_dna_sequences(dna_sequence: str) -> List[str]: # # Compute the initial hash using base-4 multiplication for i in range(dna_sequence_substr_length): rolling_hash_value = rolling_hash_value * base_a_encoding + encoded_sequence[i] - a_k *= base_a_encoding # Precompute a^k for later use in rolling hash updates + a_k *= base_a_encoding # Precompute a^k for later use in rolling hash updates - seen_hashes.add(rolling_hash_value) # Store the initial hash + seen_hashes.add(rolling_hash_value) # Store the initial hash # Sliding window approach to update the hash efficiently for start in range(1, dna_sequence_length - dna_sequence_substr_length + 1): # Remove the leftmost character and add the new rightmost character - rolling_hash_value = rolling_hash_value * base_a_encoding - encoded_sequence[start - 1] * a_k + encoded_sequence[start + dna_sequence_substr_length - 1] + rolling_hash_value = ( + rolling_hash_value * base_a_encoding + - encoded_sequence[start - 1] * a_k + + encoded_sequence[start + dna_sequence_substr_length - 1] + ) # If this hash has been seen_hashes before, add the corresponding substring to the output if rolling_hash_value in seen_hashes: - output.add(dna_sequence[start: start + dna_sequence_substr_length]) + output.add(dna_sequence[start : start + dna_sequence_substr_length]) else: seen_hashes.add(rolling_hash_value) # Convert set to list before returning return list(output) - diff --git a/algorithms/sliding_window/repeated_dna_sequences/test_repeated_dna_sequences.py b/algorithms/sliding_window/repeated_dna_sequences/test_repeated_dna_sequences.py index 5460161d..9e4687d4 100644 --- a/algorithms/sliding_window/repeated_dna_sequences/test_repeated_dna_sequences.py +++ b/algorithms/sliding_window/repeated_dna_sequences/test_repeated_dna_sequences.py @@ -29,7 +29,7 @@ def test_4(self): def test_5(self): dna_sequence = "ACGTACGTACGTACGTACGTACGTACGTACGT" - expected = ["ACGTACGTAC","CGTACGTACG","GTACGTACGT","TACGTACGTA"] + expected = ["ACGTACGTAC", "CGTACGTACG", "GTACGTACGT", "TACGTACGTA"] actual = find_repeated_dna_sequences(dna_sequence) self.assertEqual(sorted(expected), sorted(actual)) @@ -39,6 +39,7 @@ def test_6(self): actual = find_repeated_dna_sequences(dna_sequence) self.assertEqual(expected, actual) + class FindRepeatedDnaSequencesNaiveTestCase(unittest.TestCase): def test_1(self): dna_sequence = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT" @@ -66,7 +67,7 @@ def test_4(self): def test_5(self): dna_sequence = "ACGTACGTACGTACGTACGTACGTACGTACGT" - expected = ["ACGTACGTAC","CGTACGTACG","GTACGTACGT","TACGTACGTA"] + expected = ["ACGTACGTAC", "CGTACGTACG", "GTACGTACGT", "TACGTACGTA"] actual = find_repeated_dna_sequences_naive(dna_sequence) self.assertEqual(sorted(expected), sorted(actual)) @@ -76,5 +77,6 @@ def test_6(self): actual = find_repeated_dna_sequences_naive(dna_sequence) self.assertEqual(expected, actual) -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() diff --git a/algorithms/two_pointers/find_sum_of_three/__init__.py b/algorithms/two_pointers/find_sum_of_three/__init__.py index 381e3cb8..4b5f9cd4 100644 --- a/algorithms/two_pointers/find_sum_of_three/__init__.py +++ b/algorithms/two_pointers/find_sum_of_three/__init__.py @@ -17,10 +17,10 @@ def find_sum_of_three(nums: List[int], target: int) -> bool: numbers.sort() for idx, num in enumerate(numbers): - if idx > 0 and num == numbers[idx-1]: + if idx > 0 and num == numbers[idx - 1]: continue - left, right = idx+1, len(numbers) - 1 + left, right = idx + 1, len(numbers) - 1 while left < right: current_sum = num + numbers[left] + numbers[right] diff --git a/algorithms/two_pointers/find_sum_of_three/test_find_sum_of_three.py b/algorithms/two_pointers/find_sum_of_three/test_find_sum_of_three.py index 6063fee1..ff1cc83c 100644 --- a/algorithms/two_pointers/find_sum_of_three/test_find_sum_of_three.py +++ b/algorithms/two_pointers/find_sum_of_three/test_find_sum_of_three.py @@ -12,32 +12,32 @@ def test_1(self): def test2(self): """should return True for nums=[3,7,1,2,8,4,5], target=10""" - nums = [3,7,1,2,8,4,5] + nums = [3, 7, 1, 2, 8, 4, 5] target = 10 actual = find_sum_of_three(nums, target) self.assertTrue(actual) def test_3(self): """should return False for nums=[3,7,1,2,8,4,5], target=21""" - nums = [3,7,1,2,8,4,5] + nums = [3, 7, 1, 2, 8, 4, 5] target = 21 actual = find_sum_of_three(nums, target) self.assertFalse(actual) def test_4(self): """should return True for nums=[-1,2,1,-4,5,-3], target=-8""" - nums = [-1,2,1,-4,5,-3] + nums = [-1, 2, 1, -4, 5, -3] target = -8 actual = find_sum_of_three(nums, target) self.assertTrue(actual) def test_5(self): """should return True for nums=[-1,2,1,-4,5,-3], target=0""" - nums = [-1,2,1,-4,5,-3] + nums = [-1, 2, 1, -4, 5, -3] target = 0 actual = find_sum_of_three(nums, target) self.assertTrue(actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/algorithms/two_pointers/pair_with_sum_in_array/test_pair_with_sum_in_array.py b/algorithms/two_pointers/pair_with_sum_in_array/test_pair_with_sum_in_array.py index 61ed7d1b..187c3cea 100644 --- a/algorithms/two_pointers/pair_with_sum_in_array/test_pair_with_sum_in_array.py +++ b/algorithms/two_pointers/pair_with_sum_in_array/test_pair_with_sum_in_array.py @@ -20,5 +20,5 @@ def test_2(self): self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/algorithms/two_pointers/reverse_array/test_reverse_array.py b/algorithms/two_pointers/reverse_array/test_reverse_array.py index 0769e1db..052517f4 100644 --- a/algorithms/two_pointers/reverse_array/test_reverse_array.py +++ b/algorithms/two_pointers/reverse_array/test_reverse_array.py @@ -6,10 +6,10 @@ class ReverseArrayInPlaceTestCase(unittest.TestCase): def test_1(self): """should reverse an array of [1,2,3,4,5,6] in place""" collection = [1, 2, 3, 4, 5, 6] - expected = [6,5,4,3,2,1] + expected = [6, 5, 4, 3, 2, 1] reverse_array_in_place(collection) self.assertEqual(collection, expected) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/algorithms/two_pointers/sort_colors/__init__.py b/algorithms/two_pointers/sort_colors/__init__.py index 1e012c7d..ddc101ac 100644 --- a/algorithms/two_pointers/sort_colors/__init__.py +++ b/algorithms/two_pointers/sort_colors/__init__.py @@ -37,6 +37,7 @@ def sort_colors(colors: List[int]) -> List[int]: return colors + def sort_colors_v2(colors: List[int]) -> List[int]: """ Sorts a list of 0s, 1s, and 2s in place using two pointers diff --git a/algorithms/two_pointers/sort_colors/test_sort_colors.py b/algorithms/two_pointers/sort_colors/test_sort_colors.py index 41edc2a0..ff008baa 100644 --- a/algorithms/two_pointers/sort_colors/test_sort_colors.py +++ b/algorithms/two_pointers/sort_colors/test_sort_colors.py @@ -3,7 +3,6 @@ class SortColorsV2TestCase(unittest.TestCase): - def test_1(self): """should sort colors = [1,0,2,1,2,2] to [0,1,1,2,2,2]""" colors = [1, 0, 2, 1, 2, 2] @@ -13,8 +12,8 @@ def test_1(self): def test_2(self): """should sort colors = [0,1,1,2,0,2,0,2,1,2] to [0,0,0,1,1,1,2,2,2,2]""" - colors = [0,1,1,2,0,2,0,2,1,2] - expected = [0,0,0,1,1,1,2,2,2,2] + colors = [0, 1, 1, 2, 0, 2, 0, 2, 1, 2] + expected = [0, 0, 0, 1, 1, 1, 2, 2, 2, 2] actual = sort_colors_v2(colors) self.assertEqual(expected, actual) @@ -27,8 +26,8 @@ def test_3(self): def test_4(self): """should sort colors = [0,1,0] to [0,0,1]""" - colors = [0,1,0] - expected = [0,0,1] + colors = [0, 1, 0] + expected = [0, 0, 1] actual = sort_colors_v2(colors) self.assertEqual(expected, actual) @@ -41,28 +40,27 @@ def test_5(self): def test_6(self): """should sort colors = [2,2] to [2,2]""" - colors = [2,2] - expected = [2,2] + colors = [2, 2] + expected = [2, 2] actual = sort_colors_v2(colors) self.assertEqual(expected, actual) def test_7(self): """should sort colors = [1,1,0,2] to [0,1,1,2]""" - colors = [1,1,0,2] - expected = [0,1,1,2] + colors = [1, 1, 0, 2] + expected = [0, 1, 1, 2] actual = sort_colors_v2(colors) self.assertEqual(expected, actual) def test_8(self): """should sort colors = [2,1,1,0,0] to [0,0,1,1,2]""" - colors = [2,1,1,0,0] - expected = [0,0,1,1,2] + colors = [2, 1, 1, 0, 0] + expected = [0, 0, 1, 1, 2] actual = sort_colors_v2(colors) self.assertEqual(expected, actual) class SortColorsTestCase(unittest.TestCase): - def test_1(self): """should sort colors = [1,0,2,1,2,2] to [0,1,1,2,2,2]""" colors = [1, 0, 2, 1, 2, 2] @@ -72,8 +70,8 @@ def test_1(self): def test_2(self): """should sort colors = [0,1,1,2,0,2,0,2,1,2] to [0,0,0,1,1,1,2,2,2,2]""" - colors = [0,1,1,2,0,2,0,2,1,2] - expected = [0,0,0,1,1,1,2,2,2,2] + colors = [0, 1, 1, 2, 0, 2, 0, 2, 1, 2] + expected = [0, 0, 0, 1, 1, 1, 2, 2, 2, 2] actual = sort_colors(colors) self.assertEqual(expected, actual) @@ -86,8 +84,8 @@ def test_3(self): def test_4(self): """should sort colors = [0,1,0] to [0,0,1]""" - colors = [0,1,0] - expected = [0,0,1] + colors = [0, 1, 0] + expected = [0, 0, 1] actual = sort_colors(colors) self.assertEqual(expected, actual) @@ -100,24 +98,25 @@ def test_5(self): def test_6(self): """should sort colors = [2,2] to [2,2]""" - colors = [2,2] - expected = [2,2] + colors = [2, 2] + expected = [2, 2] actual = sort_colors(colors) self.assertEqual(expected, actual) def test_7(self): """should sort colors = [1,1,0,2] to [0,1,1,2]""" - colors = [1,1,0,2] - expected = [0,1,1,2] + colors = [1, 1, 0, 2] + expected = [0, 1, 1, 2] actual = sort_colors(colors) self.assertEqual(expected, actual) def test_8(self): """should sort colors = [2,1,1,0,0] to [0,0,1,1,2]""" - colors = [2,1,1,0,0] - expected = [0,0,1,1,2] + colors = [2, 1, 1, 0, 0] + expected = [0, 0, 1, 1, 2] actual = sort_colors(colors) self.assertEqual(expected, actual) -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() diff --git a/datastructures/arrays/arbitrary_precision_increment/test_arbitrary_precision_increment.py b/datastructures/arrays/arbitrary_precision_increment/test_arbitrary_precision_increment.py index ff66a93d..9a08b5ad 100644 --- a/datastructures/arrays/arbitrary_precision_increment/test_arbitrary_precision_increment.py +++ b/datastructures/arrays/arbitrary_precision_increment/test_arbitrary_precision_increment.py @@ -37,5 +37,5 @@ def test_2_2(self): self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/datastructures/arrays/array_advance_game/test_array_advance_game.py b/datastructures/arrays/array_advance_game/test_array_advance_game.py index 0933dd93..0de430ea 100644 --- a/datastructures/arrays/array_advance_game/test_array_advance_game.py +++ b/datastructures/arrays/array_advance_game/test_array_advance_game.py @@ -22,5 +22,5 @@ def test_3(self): self.assertTrue(actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/datastructures/arrays/matrix/settozero/__init__.py b/datastructures/arrays/matrix/settozero/__init__.py index 9a108808..1b8721f5 100644 --- a/datastructures/arrays/matrix/settozero/__init__.py +++ b/datastructures/arrays/matrix/settozero/__init__.py @@ -33,8 +33,8 @@ def set_matrix_zeros(mat: List[List[int]]) -> List[List[int]]: if mat[r][c] == 0: # Mark this row and column by setting the corresponding # positions in the first row and column to zero - mat[r][0] = 0 # mark row as 0 - mat[0][c] = 0 # mark column as 0 + mat[r][0] = 0 # mark row as 0 + mat[0][c] = 0 # mark column as 0 # Step 3: Use the markers to set zeros in the interior of the matrix # We process from [1][1] onwards to avoid corrupting our markers diff --git a/datastructures/arrays/matrix/settozero/test_set_matrix_zero.py b/datastructures/arrays/matrix/settozero/test_set_matrix_zero.py index cfe6ea80..0e5d4374 100644 --- a/datastructures/arrays/matrix/settozero/test_set_matrix_zero.py +++ b/datastructures/arrays/matrix/settozero/test_set_matrix_zero.py @@ -4,35 +4,47 @@ class SetMatrixZeroTestCase(unittest.TestCase): def test_1(self): - matrix = [[1,2,3],[4,5,6],[7,0,9]] - expected = [[1,0,3],[4,0,6],[0,0,0]] + matrix = [[1, 2, 3], [4, 5, 6], [7, 0, 9]] + expected = [[1, 0, 3], [4, 0, 6], [0, 0, 0]] actual = set_matrix_zeros(matrix) self.assertEqual(expected, actual) def test_2(self): - matrix = [[1,2,3,4],[4,5,6,7],[8,9,4,6]] - expected = [[1,2,3,4],[4,5,6,7],[8,9,4,6]] + matrix = [[1, 2, 3, 4], [4, 5, 6, 7], [8, 9, 4, 6]] + expected = [[1, 2, 3, 4], [4, 5, 6, 7], [8, 9, 4, 6]] actual = set_matrix_zeros(matrix) self.assertEqual(expected, actual) def test_3(self): - matrix = [[1,1,0,1,1],[1,1,1,1,1],[1,1,1,1,1],[1,0,1,1,1],[1,1,1,1,1]] - expected = [[0, 0, 0, 0, 0], [1, 0, 0, 1, 1], [1, 0, 0, 1, 1], [0, 0, 0, 0, 0], [1, 0, 0, 1, 1]] + matrix = [ + [1, 1, 0, 1, 1], + [1, 1, 1, 1, 1], + [1, 1, 1, 1, 1], + [1, 0, 1, 1, 1], + [1, 1, 1, 1, 1], + ] + expected = [ + [0, 0, 0, 0, 0], + [1, 0, 0, 1, 1], + [1, 0, 0, 1, 1], + [0, 0, 0, 0, 0], + [1, 0, 0, 1, 1], + ] actual = set_matrix_zeros(matrix) self.assertEqual(expected, actual) def test_4(self): - matrix = [[1,1,1],[1,0,1],[1,1,1]] + matrix = [[1, 1, 1], [1, 0, 1], [1, 1, 1]] expected = [[1, 0, 1], [0, 0, 0], [1, 0, 1]] actual = set_matrix_zeros(matrix) self.assertEqual(expected, actual) def test_5(self): - matrix = [[3,5,2,0],[1,0,4,6],[7,3,2,4]] + matrix = [[3, 5, 2, 0], [1, 0, 4, 6], [7, 3, 2, 4]] expected = [[0, 0, 0, 0], [0, 0, 0, 0], [7, 0, 2, 0]] actual = set_matrix_zeros(matrix) self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/datastructures/arrays/subarrays_with_fixed_bounds/test_subarrays_with_fixed_bounds.py b/datastructures/arrays/subarrays_with_fixed_bounds/test_subarrays_with_fixed_bounds.py index 73e1f7cd..aefcb380 100644 --- a/datastructures/arrays/subarrays_with_fixed_bounds/test_subarrays_with_fixed_bounds.py +++ b/datastructures/arrays/subarrays_with_fixed_bounds/test_subarrays_with_fixed_bounds.py @@ -4,7 +4,7 @@ class SubarraysWithFixedBoundsTestCase(unittest.TestCase): def test_1(self): - nums = [2,1,4,3,2] + nums = [2, 1, 4, 3, 2] min_k = 2 max_k = 3 expected = 1 @@ -12,7 +12,7 @@ def test_1(self): self.assertEqual(expected, actual) def test_2(self): - nums = [1,2,3,2,1] + nums = [1, 2, 3, 2, 1] min_k = 1 max_k = 3 expected = 5 @@ -20,7 +20,7 @@ def test_2(self): self.assertEqual(expected, actual) def test_3(self): - nums = [4,4,4] + nums = [4, 4, 4] min_k = 4 max_k = 4 expected = 6 @@ -28,7 +28,7 @@ def test_3(self): self.assertEqual(expected, actual) def test_4(self): - nums = [2,2,2] + nums = [2, 2, 2] min_k = 4 max_k = 4 expected = 0 @@ -36,7 +36,7 @@ def test_4(self): self.assertEqual(expected, actual) def test_5(self): - nums = [1,3,5,2,7,5] + nums = [1, 3, 5, 2, 7, 5] min_k = 1 max_k = 5 expected = 2 @@ -44,7 +44,7 @@ def test_5(self): self.assertEqual(expected, actual) def test_6(self): - nums = [3,3,3] + nums = [3, 3, 3] min_k = 3 max_k = 3 expected = 6 @@ -52,5 +52,5 @@ def test_6(self): self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/datastructures/linked_lists/__init__.py b/datastructures/linked_lists/__init__.py index 8ad1b28b..1262c6bc 100755 --- a/datastructures/linked_lists/__init__.py +++ b/datastructures/linked_lists/__init__.py @@ -13,7 +13,12 @@ class Node(Generic[T]): __metaclass__ = ABCMeta - def __init__(self, data: Optional[T] = None, next_: Optional['Node[Generic[T]]'] = None, key: Any = None): + def __init__( + self, + data: Optional[T] = None, + next_: Optional["Node[Generic[T]]"] = None, + key: Any = None, + ): self.data = data self.next = next_ # if no key is provided, the hash of the data becomes the key diff --git a/datastructures/linked_lists/circular/__init__.py b/datastructures/linked_lists/circular/__init__.py index 7d239c34..980cc9f8 100644 --- a/datastructures/linked_lists/circular/__init__.py +++ b/datastructures/linked_lists/circular/__init__.py @@ -5,7 +5,6 @@ class CircularLinkedList(LinkedList): - def __init__(self, head: Optional[CircularNode] = None): super().__init__(head) diff --git a/datastructures/linked_lists/circular/node.py b/datastructures/linked_lists/circular/node.py index d8f39ead..685cfce2 100644 --- a/datastructures/linked_lists/circular/node.py +++ b/datastructures/linked_lists/circular/node.py @@ -7,5 +7,7 @@ class CircularNode(Node): CircularNode implementation in a circular linked list """ - def __init__(self, value: T, next_: Optional[Self] = None, key: Optional[Any] = None): + def __init__( + self, value: T, next_: Optional[Self] = None, key: Optional[Any] = None + ): super().__init__(value, next_, key) diff --git a/datastructures/linked_lists/circular/test_circular_linked_list.py b/datastructures/linked_lists/circular/test_circular_linked_list.py index a4debea4..93801fad 100644 --- a/datastructures/linked_lists/circular/test_circular_linked_list.py +++ b/datastructures/linked_lists/circular/test_circular_linked_list.py @@ -71,5 +71,5 @@ def test_1(self): self.assertEqual(expected[1], list(second_list)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/datastructures/linked_lists/doubly_linked_list/__init__.py b/datastructures/linked_lists/doubly_linked_list/__init__.py index b67381bd..b28737e5 100755 --- a/datastructures/linked_lists/doubly_linked_list/__init__.py +++ b/datastructures/linked_lists/doubly_linked_list/__init__.py @@ -682,7 +682,6 @@ def pairs_with_sum(self, target: T) -> List[Tuple[DoubleNode, DoubleNode]]: nxt = current.next while nxt: - if current.data + nxt.data == target: pairs.append((current, nxt)) diff --git a/datastructures/linked_lists/doubly_linked_list/node.py b/datastructures/linked_lists/doubly_linked_list/node.py index c39662c4..a978adf5 100644 --- a/datastructures/linked_lists/doubly_linked_list/node.py +++ b/datastructures/linked_lists/doubly_linked_list/node.py @@ -9,11 +9,11 @@ class DoubleNode(Node): """ def __init__( - self, - data: Any, - previous: Optional["DoubleNode"] = None, - next_: Optional["DoubleNode"] = None, - key: Optional[Any] = None, + self, + data: Any, + previous: Optional["DoubleNode"] = None, + next_: Optional["DoubleNode"] = None, + key: Optional[Any] = None, ): super().__init__(data=data, next_=next_, key=key) self.previous = previous diff --git a/datastructures/linked_lists/mergeklinkedlists/__init__.py b/datastructures/linked_lists/mergeklinkedlists/__init__.py index cc3e3026..878df547 100644 --- a/datastructures/linked_lists/mergeklinkedlists/__init__.py +++ b/datastructures/linked_lists/mergeklinkedlists/__init__.py @@ -2,7 +2,9 @@ from .. import Node -def merge_two_sorted_lists(head_one: Optional[Node], head_two: Optional[Node]) -> Optional[Node]: +def merge_two_sorted_lists( + head_one: Optional[Node], head_two: Optional[Node] +) -> Optional[Node]: """ Merges two sorted linked list into 1 sorted linked list. Note that the assumption here is that the 2 linked lists are already sorted. If either of the heads of the linked list that is provided is None, the other head node is diff --git a/datastructures/linked_lists/mergeklinkedlists/test_merge.py b/datastructures/linked_lists/mergeklinkedlists/test_merge.py index 953cbe00..256835a7 100644 --- a/datastructures/linked_lists/mergeklinkedlists/test_merge.py +++ b/datastructures/linked_lists/mergeklinkedlists/test_merge.py @@ -45,7 +45,11 @@ def test_2_merge_3_linked_lists(self): for data in l3: linked_list_three.append(data) - linked_lists = [linked_list_one.head, linked_list_two.head, linked_list_three.head] + linked_lists = [ + linked_list_one.head, + linked_list_two.head, + linked_list_three.head, + ] actual = merge_k_lists(linked_lists) self.assertIsNotNone(actual) @@ -59,5 +63,5 @@ def test_2_merge_3_linked_lists(self): self.assertEqual(expected, actual_data) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/datastructures/linked_lists/singly_linked_list/__init__.py b/datastructures/linked_lists/singly_linked_list/__init__.py index 4094c7f6..a564ce79 100755 --- a/datastructures/linked_lists/singly_linked_list/__init__.py +++ b/datastructures/linked_lists/singly_linked_list/__init__.py @@ -134,7 +134,9 @@ def delete_node_at_position(self, position: int) -> Optional[SingleNode]: current = current.next if current is None: - raise ValueError(f"Invalid position {position} found, reached end of list") + raise ValueError( + f"Invalid position {position} found, reached end of list" + ) current.data = current.next.data if current.next else None current.next = current.next.next if current.next else None diff --git a/datastructures/linked_lists/singly_linked_list/test_singly_linked_list_remove_nth_last_node.py b/datastructures/linked_lists/singly_linked_list/test_singly_linked_list_remove_nth_last_node.py index eb63da52..f12df193 100644 --- a/datastructures/linked_lists/singly_linked_list/test_singly_linked_list_remove_nth_last_node.py +++ b/datastructures/linked_lists/singly_linked_list/test_singly_linked_list_remove_nth_last_node.py @@ -3,7 +3,6 @@ class RemoveNthLastNodeTestCases(unittest.TestCase): - def test_0(self): """should raise ValueError when the value of n is out of bounds""" linked_list = SinglyLinkedList() @@ -76,13 +75,13 @@ def test_4(self): def test_5(self): """should delete nth last node where n=6 and list is [69,8,49,106,116,112] to become [8,49,106,116,112]""" linked_list = SinglyLinkedList() - data = [69,8,49,106,116,112] + data = [69, 8, 49, 106, 116, 112] for d in data: linked_list.append(d) n = 6 new_head = linked_list.delete_nth_last_node(n) - expected = [8,49,106,116,112] + expected = [8, 49, 106, 116, 112] self.assertIsNotNone(new_head) self.assertEqual(new_head.data, 8) @@ -106,13 +105,13 @@ def test_6(self): def test_7(self): """should delete nth last node where n=4 and list is [288,224,275,390,4,383,330,60,193] to become [288,224,275,390,4,330,60,193]""" linked_list = SinglyLinkedList() - data = [288,224,275,390,4,383,330,60,193] + data = [288, 224, 275, 390, 4, 383, 330, 60, 193] for d in data: linked_list.append(d) n = 4 new_head = linked_list.delete_nth_last_node(n) - expected = [288,224,275,390,4,330,60,193] + expected = [288, 224, 275, 390, 4, 330, 60, 193] self.assertIsNotNone(new_head) self.assertEqual(new_head.data, 288) @@ -121,13 +120,13 @@ def test_7(self): def test_8(self): """should delete nth last node where n=3 and list is [34,53,6,95,38,28,17,63,16,76] to become [34,53,6,95,38,28,17,16,76]""" linked_list = SinglyLinkedList() - data = [34,53,6,95,38,28,17,63,16,76] + data = [34, 53, 6, 95, 38, 28, 17, 63, 16, 76] for d in data: linked_list.append(d) n = 3 new_head = linked_list.delete_nth_last_node(n) - expected = [34,53,6,95,38,28,17,16,76] + expected = [34, 53, 6, 95, 38, 28, 17, 16, 76] self.assertIsNotNone(new_head) self.assertEqual(new_head.data, 34) @@ -136,18 +135,18 @@ def test_8(self): def test_9(self): """should delete nth last node where n=2 and list is [23,28,10,5,67,39,70,28] to become [23,28,10,5,67,39,28]""" linked_list = SinglyLinkedList() - data = [23,28,10,5,67,39,70,28] + data = [23, 28, 10, 5, 67, 39, 70, 28] for d in data: linked_list.append(d) n = 2 new_head = linked_list.delete_nth_last_node(n) - expected = [23,28,10,5,67,39,28] + expected = [23, 28, 10, 5, 67, 39, 28] self.assertIsNotNone(new_head) self.assertEqual(new_head.data, 23) self.assertEqual(expected, list(linked_list)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/datastructures/linked_lists/singly_linked_list/test_singly_linked_palindrome.py b/datastructures/linked_lists/singly_linked_list/test_singly_linked_palindrome.py index 020d7ad5..63a3d44d 100644 --- a/datastructures/linked_lists/singly_linked_list/test_singly_linked_palindrome.py +++ b/datastructures/linked_lists/singly_linked_list/test_singly_linked_palindrome.py @@ -49,7 +49,7 @@ def test_4(self): def test_5(self): """should return true for [1,2,3,2,1]""" linked_list = SinglyLinkedList() - data = [1,2,3,2,1] + data = [1, 2, 3, 2, 1] for d in data: linked_list.append(d) @@ -59,7 +59,7 @@ def test_5(self): def test_6(self): """should return true for [4,7,9,5,4]""" linked_list = SinglyLinkedList() - data = [4,7,9,5,4] + data = [4, 7, 9, 5, 4] for d in data: linked_list.append(d) @@ -69,7 +69,7 @@ def test_6(self): def test_7(self): """should return true for [2,3,5,5,3,2]""" linked_list = SinglyLinkedList() - data = [2,3,5,5,3,2] + data = [2, 3, 5, 5, 3, 2] for d in data: linked_list.append(d) @@ -79,28 +79,29 @@ def test_7(self): def test_8(self): """should return true for [6,1,0,5,1,6]""" linked_list = SinglyLinkedList() - data = [6,1,0,5,1,6] + data = [6, 1, 0, 5, 1, 6] for d in data: linked_list.append(d) actual = linked_list.is_palindrome() self.assertFalse(actual) - def test_9(self): """should return true for [3,6,9,8,4,8,9,6,3]""" linked_list = SinglyLinkedList() - data = [3,6,9,8,4,8,9,6,3] + data = [3, 6, 9, 8, 4, 8, 9, 6, 3] for d in data: linked_list.append(d) actual = linked_list.is_palindrome() self.assertTrue(actual) + class LinkedListIsPalindromeV2TestCase(unittest.TestCase): """ Tests to check if a linked list is a palindrome using fast and slow pointers approach """ + @pytest.mark.linked_list_is_palindrome_fast_and_slow_pointer def test_1(self): """should return true for ["r", "a", "c", "e", "c", "a", "r"]""" @@ -149,7 +150,7 @@ def test_4(self): def test_5(self): """should return true for [1,2,3,2,1]""" linked_list = SinglyLinkedList() - data = [1,2,3,2,1] + data = [1, 2, 3, 2, 1] for d in data: linked_list.append(d) @@ -160,7 +161,7 @@ def test_5(self): def test_6(self): """should return true for [4,7,9,5,4]""" linked_list = SinglyLinkedList() - data = [4,7,9,5,4] + data = [4, 7, 9, 5, 4] for d in data: linked_list.append(d) @@ -171,7 +172,7 @@ def test_6(self): def test_7(self): """should return true for [2,3,5,5,3,2]""" linked_list = SinglyLinkedList() - data = [2,3,5,5,3,2] + data = [2, 3, 5, 5, 3, 2] for d in data: linked_list.append(d) @@ -182,7 +183,7 @@ def test_7(self): def test_8(self): """should return false for [6,1,0,5,1,6]""" linked_list = SinglyLinkedList() - data = [6,1,0,5,1,6] + data = [6, 1, 0, 5, 1, 6] for d in data: linked_list.append(d) @@ -193,7 +194,7 @@ def test_8(self): def test_9(self): """should return true for [3,6,9,8,4,8,9,6,3]""" linked_list = SinglyLinkedList() - data = [3,6,9,8,4,8,9,6,3] + data = [3, 6, 9, 8, 4, 8, 9, 6, 3] for d in data: linked_list.append(d) diff --git a/datastructures/trees/__init__.py b/datastructures/trees/__init__.py index 6f427d2b..8df8929a 100755 --- a/datastructures/trees/__init__.py +++ b/datastructures/trees/__init__.py @@ -33,7 +33,7 @@ def height(self) -> int: @abstractmethod def lowest_common_ancestor( - self, node_one: TreeNode, node_two: TreeNode + self, node_one: TreeNode, node_two: TreeNode ) -> TreeNode: """ Returns the lowest common ancestor of 2 nodes in the Tree. diff --git a/datastructures/trees/binary/node.py b/datastructures/trees/binary/node.py index f659e9cb..6d869246 100644 --- a/datastructures/trees/binary/node.py +++ b/datastructures/trees/binary/node.py @@ -9,11 +9,11 @@ class BinaryTreeNode(TreeNode): """ def __init__( - self, - data: T, - left: Optional["BinaryTreeNode"] = None, - right: Optional["BinaryTreeNode"] = None, - key: Optional[Any] = None + self, + data: T, + left: Optional["BinaryTreeNode"] = None, + right: Optional["BinaryTreeNode"] = None, + key: Optional[Any] = None, ): super().__init__(data, key) self.left: Optional[BinaryTreeNode] = left diff --git a/datastructures/trees/binary/search_tree/__init__.py b/datastructures/trees/binary/search_tree/__init__.py index 8108f0e8..da6e03ca 100755 --- a/datastructures/trees/binary/search_tree/__init__.py +++ b/datastructures/trees/binary/search_tree/__init__.py @@ -54,7 +54,7 @@ def delete_node(self, key: T) -> Optional[BinaryTreeNode]: return self.root def delete_helper( - value: T, node: Optional[BinaryTreeNode] + value: T, node: Optional[BinaryTreeNode] ) -> Optional[BinaryTreeNode]: # base case when we have hit the bottom of the tree, and the parent node has no children if node is None: @@ -88,7 +88,7 @@ def delete_helper( return node def lift( - node: BinaryTreeNode, node_to_delete: BinaryTreeNode + node: BinaryTreeNode, node_to_delete: BinaryTreeNode ) -> BinaryTreeNode: # if the current node of this function has a left child, we recursively call this function to continue down # the left subtree to find the successor node @@ -530,7 +530,7 @@ def is_binary_search_tree(self): return True def is_binary_search_tree_recursive( - self, root: BinaryTreeNode, lower_bound=-float("inf"), upper_bound=float("inf") + self, root: BinaryTreeNode, lower_bound=-float("inf"), upper_bound=float("inf") ): """ This uses the call stack to check if the binary search tree node is valid. @@ -551,10 +551,10 @@ def is_binary_search_tree_recursive( return False return not ( - not self.is_binary_search_tree_recursive(root.left, lower_bound, root.data) - or not self.is_binary_search_tree_recursive( - root.right, root.data, upper_bound - ) + not self.is_binary_search_tree_recursive(root.left, lower_bound, root.data) + or not self.is_binary_search_tree_recursive( + root.right, root.data, upper_bound + ) ) def search_node(self, data: T) -> bool: @@ -639,7 +639,7 @@ def is_balanced(self) -> bool: # 1) more than 2 different leaf depths # 2) 2 leaf depths that are more than 1 apart if len(depths) > 2 or ( - len(depths) == 2 and abs(depths[0] - depths[1]) > 1 + len(depths) == 2 and abs(depths[0] - depths[1]) > 1 ): return False @@ -653,7 +653,7 @@ def is_balanced(self) -> bool: return True def lowest_common_ancestor( - self, node_one: BinaryTreeNode, node_two: BinaryTreeNode + self, node_one: BinaryTreeNode, node_two: BinaryTreeNode ) -> BinaryTreeNode: """ Considering it is a BST, we can assume that this tree is a valid BST, we could also check for this diff --git a/datastructures/trees/binary/search_tree/test_binary_search_tree_insert.py b/datastructures/trees/binary/search_tree/test_binary_search_tree_insert.py index 0a322030..d1b2e8ee 100644 --- a/datastructures/trees/binary/search_tree/test_binary_search_tree_insert.py +++ b/datastructures/trees/binary/search_tree/test_binary_search_tree_insert.py @@ -15,9 +15,7 @@ def test_1(self): expected_root = BinaryTreeNode( data=8, left=BinaryTreeNode( - data=3, - left=BinaryTreeNode(data=1), - right=BinaryTreeNode(data=6) + data=3, left=BinaryTreeNode(data=1), right=BinaryTreeNode(data=6) ), right=BinaryTreeNode(data=10), ) @@ -26,7 +24,9 @@ def test_1(self): self.assertEqual(expected_root.left.data, search_tree.root.left.data) self.assertEqual(expected_root.right.data, search_tree.root.right.data) self.assertEqual(expected_root.left.left.data, search_tree.root.left.left.data) - self.assertEqual(expected_root.left.right.data, search_tree.root.left.right.data) + self.assertEqual( + expected_root.left.right.data, search_tree.root.left.right.data + ) if __name__ == "__main__": diff --git a/datastructures/trees/binary/tree/__init__.py b/datastructures/trees/binary/tree/__init__.py index bf7cbf1a..0cc61d6f 100644 --- a/datastructures/trees/binary/tree/__init__.py +++ b/datastructures/trees/binary/tree/__init__.py @@ -219,7 +219,7 @@ def flatten_into_linked_list(self) -> None: tree_node.left = None def lowest_common_ancestor( - self, node_one: BinaryTreeNode, node_two: BinaryTreeNode + self, node_one: BinaryTreeNode, node_two: BinaryTreeNode ) -> Optional[BinaryTreeNode]: """ The approach is pretty intuitive. Traverse the tree in a depth first manner. The moment you encounter either of @@ -263,10 +263,10 @@ def lowest_common_ancestor( return None def lca_util( - node: Optional[BinaryTreeNode], - node_one_value: T, - node_two_val: T, - node_lookup: List[bool], + node: Optional[BinaryTreeNode], + node_one_value: T, + node_two_val: T, + node_lookup: List[bool], ) -> Optional[BinaryTreeNode]: """Returns the Lowest Common Ancestor of 2 node values.This updates a node lookup list that has 2 values. The first index is for node_one_value and the second index is for node_two_value. They will be updated to @@ -309,9 +309,9 @@ def is_key_in_subtree(current_node: Optional[BinaryTreeNode], key: T) -> bool: # If key is present at root, or if left subtree or right subtree , return true if ( - current_node.data == key - or is_key_in_subtree(current_node.left, key) - or is_key_in_subtree(current_node.right, key) + current_node.data == key + or is_key_in_subtree(current_node.left, key) + or is_key_in_subtree(current_node.right, key) ): return True @@ -321,12 +321,12 @@ def is_key_in_subtree(current_node: Optional[BinaryTreeNode], key: T) -> bool: lca = lca_util(self.root, node_one.data, node_two.data, lookup) if ( - lookup[0] - and lookup[1] - or lookup[0] - and is_key_in_subtree(lca, node_two.data) - or lookup[1] - and is_key_in_subtree(lca, node_one.data) + lookup[0] + and lookup[1] + or lookup[0] + and is_key_in_subtree(lca, node_two.data) + or lookup[1] + and is_key_in_subtree(lca, node_one.data) ): return lca @@ -461,7 +461,7 @@ def is_height_balanced(node: BinaryTreeNode) -> bool: def leaf_similar(self, other: "BinaryTree") -> bool: if (self.root is None and other.root is not None) or ( - other.root is None and self.root is not None + other.root is None and self.root is not None ): return False @@ -503,7 +503,7 @@ def path_sum(self, target: T) -> int: return 0 def count_paths( - sum_hash: Dict[int, int], prefix_sum: T, node: BinaryTreeNode + sum_hash: Dict[int, int], prefix_sum: T, node: BinaryTreeNode ) -> int: if node is None: return 0 @@ -559,10 +559,10 @@ def paths_to_target(self, target: T) -> List[T]: return paths def dfs( - node: Optional[BinaryTreeNode], - path: List[T], - result: List, - remaining_sum: T, + node: Optional[BinaryTreeNode], + path: List[T], + result: List, + remaining_sum: T, ): """Traverses the tree from root to leaf paths in a depth first search manner. diff --git a/datastructures/trees/binary/tree/test_binary_tree.py b/datastructures/trees/binary/tree/test_binary_tree.py index d1880a6e..f4550e19 100644 --- a/datastructures/trees/binary/tree/test_binary_tree.py +++ b/datastructures/trees/binary/tree/test_binary_tree.py @@ -220,7 +220,9 @@ def test_returns_1_for_root_but_no_children(self): def test_returns_3_for_tree_3_9_20_null_null_15_7(self): """should return 3 if the binary tree [3,9,20,null,null,15,7]""" left = BinaryTreeNode(data=9) - right = BinaryTreeNode(data=20, left=BinaryTreeNode(data=15), right=BinaryTreeNode(data=7)) + right = BinaryTreeNode( + data=20, left=BinaryTreeNode(data=15), right=BinaryTreeNode(data=7) + ) root = BinaryTreeNode(data=3, left=left, right=right) tree = BinaryTree(root=root) @@ -243,7 +245,9 @@ def test_returns_2_for_tree_1_null_20(self): def test_returns_2_for_tree_1_2_3_4_5(self): """should return 2 if the binary tree [1,2,3,4,5]""" right = BinaryTreeNode(data=3) - left = BinaryTreeNode(data=2, left=BinaryTreeNode(data=4), right=BinaryTreeNode(5)) + left = BinaryTreeNode( + data=2, left=BinaryTreeNode(data=4), right=BinaryTreeNode(5) + ) root = BinaryTreeNode(data=1, left=left, right=right) tree = BinaryTree(root=root) @@ -272,7 +276,9 @@ def test_returns_1_for_root_but_no_children(self): def test_returns_5_for_tree_3_9_20_null_null_15_7(self): """should return 5 if the binary tree [3,9,20,null,null,15,7]""" left = BinaryTreeNode(data=9) - right = BinaryTreeNode(data=20, left=BinaryTreeNode(data=15), right=BinaryTreeNode(data=7)) + right = BinaryTreeNode( + data=20, left=BinaryTreeNode(data=15), right=BinaryTreeNode(data=7) + ) root = BinaryTreeNode(data=3, left=left, right=right) tree = BinaryTree(root=root) @@ -295,7 +301,9 @@ def test_returns_2_for_tree_1_null_20(self): def test_returns_5_for_tree_1_2_3_4_5(self): """should return 5 if the binary tree [1,2,3,4,5]""" right = BinaryTreeNode(data=3) - left = BinaryTreeNode(data=2, left=BinaryTreeNode(data=4), right=BinaryTreeNode(5)) + left = BinaryTreeNode( + data=2, left=BinaryTreeNode(data=4), right=BinaryTreeNode(5) + ) root = BinaryTreeNode(data=1, left=left, right=right) tree = BinaryTree(root=root) @@ -706,8 +714,13 @@ def test_1(self): """Should return [F,B,A,D,C,E,G,I,H]""" expected = ["F", "B", "A", "D", "C", "E", "G", "I", "H"] right = BinaryTreeNode("G", right=BinaryTreeNode("I", left=BinaryTreeNode("H"))) - left = BinaryTreeNode("B", left=BinaryTreeNode("A"), - right=BinaryTreeNode("D", left=BinaryTreeNode("C"), right=BinaryTreeNode("E"))) + left = BinaryTreeNode( + "B", + left=BinaryTreeNode("A"), + right=BinaryTreeNode( + "D", left=BinaryTreeNode("C"), right=BinaryTreeNode("E") + ), + ) root = BinaryTreeNode("F", left=left, right=right) tree = BinaryTree(root=root) @@ -720,8 +733,13 @@ def test_1(self): """Should return [A, B, C, D, E, F, G, H, I]""" expected = ["A", "B", "C", "D", "E", "F", "G", "H", "I"] right = BinaryTreeNode("G", right=BinaryTreeNode("I", left=BinaryTreeNode("H"))) - left = BinaryTreeNode("B", left=BinaryTreeNode("A"), - right=BinaryTreeNode("D", left=BinaryTreeNode("C"), right=BinaryTreeNode("E"))) + left = BinaryTreeNode( + "B", + left=BinaryTreeNode("A"), + right=BinaryTreeNode( + "D", left=BinaryTreeNode("C"), right=BinaryTreeNode("E") + ), + ) root = BinaryTreeNode("F", left=left, right=right) tree = BinaryTree(root=root) @@ -734,8 +752,13 @@ def test_1(self): """Should return [A, C, E, D, B, H, I, G, F]""" expected = ["A", "C", "E", "D", "B", "H", "I", "G", "F"] right = BinaryTreeNode("G", right=BinaryTreeNode("I", left=BinaryTreeNode("H"))) - left = BinaryTreeNode("B", left=BinaryTreeNode("A"), - right=BinaryTreeNode("D", left=BinaryTreeNode("C"), right=BinaryTreeNode("E"))) + left = BinaryTreeNode( + "B", + left=BinaryTreeNode("A"), + right=BinaryTreeNode( + "D", left=BinaryTreeNode("C"), right=BinaryTreeNode("E") + ), + ) root = BinaryTreeNode("F", left=left, right=right) tree = BinaryTree(root=root) @@ -748,8 +771,7 @@ def test_1(self): """Should return [1, 2, 3, 4, 5]""" expected = [1, 2, 3, 4, 5] right = BinaryTreeNode(3) - left = BinaryTreeNode(2, left=BinaryTreeNode(4), - right=BinaryTreeNode(5)) + left = BinaryTreeNode(2, left=BinaryTreeNode(4), right=BinaryTreeNode(5)) root = BinaryTreeNode(1, left=left, right=right) tree = BinaryTree(root=root) @@ -762,8 +784,7 @@ def test_1(self): """Should return [4, 5, 2, 3, 1]""" expected = [4, 5, 2, 3, 1] right = BinaryTreeNode(3) - left = BinaryTreeNode(2, left=BinaryTreeNode(4), - right=BinaryTreeNode(5)) + left = BinaryTreeNode(2, left=BinaryTreeNode(4), right=BinaryTreeNode(5)) root = BinaryTreeNode(1, left=left, right=right) tree = BinaryTree(root=root) diff --git a/puzzles/arrays/maxlen_contiguous_binary_subarray/test_maxlen_contiguous_binary_subarray.py b/puzzles/arrays/maxlen_contiguous_binary_subarray/test_maxlen_contiguous_binary_subarray.py index eff8f046..730fb49a 100644 --- a/puzzles/arrays/maxlen_contiguous_binary_subarray/test_maxlen_contiguous_binary_subarray.py +++ b/puzzles/arrays/maxlen_contiguous_binary_subarray/test_maxlen_contiguous_binary_subarray.py @@ -1,5 +1,5 @@ import unittest - +import random from . import find_max_length @@ -50,7 +50,6 @@ def test_0_0_1_1_1_0_0_0_0_0_returns_6(self): self.assertEqual(expected, actual) -@test.describe("Random Tests") def tests(): def check(s) -> int: Track, balance, index, len1 = {}, 0, 0, 0 @@ -83,7 +82,6 @@ def shuffs(s): test.assert_equals(binarray(s.copy()), answer) def rnd_tests(title, l, m, flag): - @test.it(title + " size") def _(): for _ in range(l): if flag: diff --git a/puzzles/arrays/tournament_winner/test_tournament_winner.py b/puzzles/arrays/tournament_winner/test_tournament_winner.py index 632eaf0d..8afae182 100644 --- a/puzzles/arrays/tournament_winner/test_tournament_winner.py +++ b/puzzles/arrays/tournament_winner/test_tournament_winner.py @@ -1,6 +1,7 @@ import unittest from . import tournament_winner + class TournamentWinnerTestCase(unittest.TestCase): def test_1(self): competitions = [["HTML", "C#"], ["C#", "Python"], ["Python", "HTML"]] @@ -10,12 +11,12 @@ def test_1(self): self.assertEqual(expected, actual) def test_2(self): - competitions = [["HTML", "Java"],["Java", "Python"],["Python", "HTML"]] + competitions = [["HTML", "Java"], ["Java", "Python"], ["Python", "HTML"]] results = [0, 1, 1] expected = "Java" actual = tournament_winner(competitions, results) self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/puzzles/permutations_check/__init__.py b/puzzles/permutations_check/__init__.py index 4c06dbb0..5ebbfc43 100644 --- a/puzzles/permutations_check/__init__.py +++ b/puzzles/permutations_check/__init__.py @@ -6,11 +6,10 @@ def check(n: int, m: int, games: List[List[int]]) -> bool: for game_round in games: for i, j in pairs: - - if i in game_round[:n // 2] and j in game_round[:n // 2]: + if i in game_round[: n // 2] and j in game_round[: n // 2]: return False - if i in game_round[n // 2:] and j in game_round[n // 2:]: + if i in game_round[n // 2 :] and j in game_round[n // 2 :]: return False return True diff --git a/puzzles/permutations_check/test_check.py b/puzzles/permutations_check/test_check.py index 6d096343..1f722dc6 100644 --- a/puzzles/permutations_check/test_check.py +++ b/puzzles/permutations_check/test_check.py @@ -30,24 +30,36 @@ def test_3(self): def test_4(self): """should return False for n = 6, m = 6, games=[[1, 6, 4, 5, 2], [6, 4, 2, 3, 1, 5], [4, 2, 1, 5, 6, 3], [4, 5, 1, 6, 2, 3], [3, 2, 5, 1, 6, 4], - [2, 3, 6, 4, 1, 5]]""" + [2, 3, 6, 4, 1, 5]]""" n = 6 m = 6 - games = [[1, 6, 4, 5, 2], [6, 4, 2, 3, 1, 5], [4, 2, 1, 5, 6, 3], [4, 5, 1, 6, 2, 3], [3, 2, 5, 1, 6, 4], - [2, 3, 6, 4, 1, 5]] + games = [ + [1, 6, 4, 5, 2], + [6, 4, 2, 3, 1, 5], + [4, 2, 1, 5, 6, 3], + [4, 5, 1, 6, 2, 3], + [3, 2, 5, 1, 6, 4], + [2, 3, 6, 4, 1, 5], + ] actual = check(n, m, games) self.assertTrue(actual) def test_5(self): """should return False for n = 6, m = 6, games=[[3, 1, 4, 5, 6, 2], [5, 3, 2, 4, 1, 6], [5, 3, 6, 4, 2, 1], [6, 5, 3, 2, 1, 4], [5, 4, 1, 2, 6, 3], - [4, 1, 6, 2, 5, 3]]""" + [4, 1, 6, 2, 5, 3]]""" n = 6 m = 6 - games = [[3, 1, 4, 5, 6, 2], [5, 3, 2, 4, 1, 6], [5, 3, 6, 4, 2, 1], [6, 5, 3, 2, 1, 4], [5, 4, 1, 2, 6, 3], - [4, 1, 6, 2, 5, 3]] + games = [ + [3, 1, 4, 5, 6, 2], + [5, 3, 2, 4, 1, 6], + [5, 3, 6, 4, 2, 1], + [6, 5, 3, 2, 1, 4], + [5, 4, 1, 2, 6, 3], + [4, 1, 6, 2, 5, 3], + ] actual = check(n, m, games) self.assertFalse(actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/puzzles/product_of_two_positive_integers/__init__.py b/puzzles/product_of_two_positive_integers/__init__.py index 7233e703..fda0d2c6 100644 --- a/puzzles/product_of_two_positive_integers/__init__.py +++ b/puzzles/product_of_two_positive_integers/__init__.py @@ -11,4 +11,4 @@ def recursive_multiply(x: int, y: int) -> int: return recursive_multiply(y, x) if y == 0: return 0 - return x + recursive_multiply(x, y - 1) \ No newline at end of file + return x + recursive_multiply(x, y - 1) diff --git a/puzzles/product_of_two_positive_integers/test_recursive_multiply.py b/puzzles/product_of_two_positive_integers/test_recursive_multiply.py index cc064fef..0066a0fd 100644 --- a/puzzles/product_of_two_positive_integers/test_recursive_multiply.py +++ b/puzzles/product_of_two_positive_integers/test_recursive_multiply.py @@ -7,7 +7,7 @@ def test_1(self): """should return 15 from 5 and 3""" x = 5 y = 3 - expected = x*y + expected = x * y actual = recursive_multiply(x, y) self.assertEqual(expected, actual) @@ -15,9 +15,10 @@ def test_2(self): """should return 1000000 from 500 and 2000""" x = 500 y = 2000 - expected = x*y + expected = x * y actual = recursive_multiply(x, y) self.assertEqual(expected, actual) -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() diff --git a/puzzles/search/binary_search/cyclically_shifted_array/__init__.py b/puzzles/search/binary_search/cyclically_shifted_array/__init__.py index b194333a..809f2334 100644 --- a/puzzles/search/binary_search/cyclically_shifted_array/__init__.py +++ b/puzzles/search/binary_search/cyclically_shifted_array/__init__.py @@ -1,5 +1,6 @@ from typing import List + def find_index_of_smallest_number(numbers: List[int]) -> int: """ Finds the index of the smallest number in a cyclically shifted array diff --git a/puzzles/search/binary_search/cyclically_shifted_array/test_cyclically_shifted_array.py b/puzzles/search/binary_search/cyclically_shifted_array/test_cyclically_shifted_array.py index bdf5417b..201f2e23 100644 --- a/puzzles/search/binary_search/cyclically_shifted_array/test_cyclically_shifted_array.py +++ b/puzzles/search/binary_search/cyclically_shifted_array/test_cyclically_shifted_array.py @@ -52,5 +52,6 @@ def test_7(self): actual = find_index_of_smallest_number(numbers) self.assertEqual(expected, actual) -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() diff --git a/puzzles/search/binary_search/find_closest_number/test_find_closest_number.py b/puzzles/search/binary_search/find_closest_number/test_find_closest_number.py index 5786a172..c065a18b 100644 --- a/puzzles/search/binary_search/find_closest_number/test_find_closest_number.py +++ b/puzzles/search/binary_search/find_closest_number/test_find_closest_number.py @@ -22,5 +22,5 @@ def test_2(self): self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/puzzles/search/binary_search/find_closest_value/test_find_closest_value.py b/puzzles/search/binary_search/find_closest_value/test_find_closest_value.py index bc01c3cf..5c8b4e29 100644 --- a/puzzles/search/binary_search/find_closest_value/test_find_closest_value.py +++ b/puzzles/search/binary_search/find_closest_value/test_find_closest_value.py @@ -7,25 +7,24 @@ class FindClosestValueTestCases(unittest.TestCase): def test_something(self): root = BinaryTreeNode( data=10, - left=BinaryTreeNode(data=5, - left=BinaryTreeNode( - data=2, - left=BinaryTreeNode(data=1), - right=BinaryTreeNode(data=5)) - ), - right=BinaryTreeNode(data=15, - left=BinaryTreeNode( - data=13, - right=BinaryTreeNode( - data=14, - right=BinaryTreeNode(data=22) - ) - )) + left=BinaryTreeNode( + data=5, + left=BinaryTreeNode( + data=2, left=BinaryTreeNode(data=1), right=BinaryTreeNode(data=5) + ), + ), + right=BinaryTreeNode( + data=15, + left=BinaryTreeNode( + data=13, + right=BinaryTreeNode(data=14, right=BinaryTreeNode(data=22)), + ), + ), ) expected = 13 actual = find_closest_value_in_bst(root, target=12) self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/puzzles/search/binary_search/find_first_in_duplicate_list/__init__.py b/puzzles/search/binary_search/find_first_in_duplicate_list/__init__.py index 360aae16..d5eba3d2 100644 --- a/puzzles/search/binary_search/find_first_in_duplicate_list/__init__.py +++ b/puzzles/search/binary_search/find_first_in_duplicate_list/__init__.py @@ -1,7 +1,7 @@ from typing import List, Optional -def find_first_in_duplicates_linear(numbers: List[int], target:int) -> Optional[int]: +def find_first_in_duplicates_linear(numbers: List[int], target: int) -> Optional[int]: """ Finds the first duplicate number that matches the target from the sorted numbers list. if not found, None is returned. @@ -26,7 +26,7 @@ def find_first_in_duplicates_linear(numbers: List[int], target:int) -> Optional[ return None -def find_first_in_duplicates(numbers: List[int], target:int) -> Optional[int]: +def find_first_in_duplicates(numbers: List[int], target: int) -> Optional[int]: """ Finds the first duplicate number that matches the target from the sorted numbers list. if not found, None is returned. @@ -51,11 +51,11 @@ def find_first_in_duplicates(numbers: List[int], target:int) -> Optional[int]: # If the middle number is less than the target, we move the low/left pointer to the middle + 1, eliminating the # left portion of the list if numbers[mid] < target: - low = mid +1 + low = mid + 1 elif numbers[mid] > target: # if the middle number is greater than the target, we move the right/high pointer to the middle-1, removing # the right portion of the list - high = mid -1 + high = mid - 1 else: # This else block addresses finding the first occurrence of the target element. This block is entered when # the target is equal to numbers[mid]. Since the list is sorted in ascending order, the target is either the @@ -66,7 +66,7 @@ def find_first_in_duplicates(numbers: List[int], target:int) -> Optional[int]: return mid # next is to check if the element to the left of numbers[mid], i.e. numbers[mid-1] is the target or not. It # is not, this evaluates to true and implies that numbers[mid] is the first occurrence, so mid is returned - if numbers[mid -1] != target: + if numbers[mid - 1] != target: return mid # However, if the element on the left is also the same as the target element, we update high to mid - 1. This # way, we condense our search space to find the first occurrence of the target which will be on the left of diff --git a/puzzles/search/binary_search/find_first_in_duplicate_list/test_find_first_in_duplicates.py b/puzzles/search/binary_search/find_first_in_duplicate_list/test_find_first_in_duplicates.py index 0f353f4a..ba843d7c 100644 --- a/puzzles/search/binary_search/find_first_in_duplicate_list/test_find_first_in_duplicates.py +++ b/puzzles/search/binary_search/find_first_in_duplicate_list/test_find_first_in_duplicates.py @@ -11,6 +11,7 @@ def test_1(self): actual = find_first_in_duplicates_linear(numbers, target) self.assertEqual(expected, actual) + class FindFirstEntryInDuplicateListTestCases(unittest.TestCase): def test_1(self): """should return 3 for numbers=[-14, -10, 2, 108, 108, 243, 285, 285, 285, 401] and target=108""" @@ -21,5 +22,5 @@ def test_1(self): self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/puzzles/search/binary_search/find_fixed_number/test_find_fixed_number.py b/puzzles/search/binary_search/find_fixed_number/test_find_fixed_number.py index 46f81351..a1e12291 100644 --- a/puzzles/search/binary_search/find_fixed_number/test_find_fixed_number.py +++ b/puzzles/search/binary_search/find_fixed_number/test_find_fixed_number.py @@ -44,5 +44,5 @@ def test_fixed_point_linear_3(self): self.assertIsNone(actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/puzzles/search/binary_search/integer_square_root/test_integer_square_root.py b/puzzles/search/binary_search/integer_square_root/test_integer_square_root.py index 5355a0ca..abc1405c 100644 --- a/puzzles/search/binary_search/integer_square_root/test_integer_square_root.py +++ b/puzzles/search/binary_search/integer_square_root/test_integer_square_root.py @@ -18,5 +18,5 @@ def test_3(self): self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/puzzles/stack/decimal_to_binary/test_decimal_to_binary.py b/puzzles/stack/decimal_to_binary/test_decimal_to_binary.py index 0cc130cd..2af19c6a 100644 --- a/puzzles/stack/decimal_to_binary/test_decimal_to_binary.py +++ b/puzzles/stack/decimal_to_binary/test_decimal_to_binary.py @@ -28,5 +28,5 @@ def test_10(self): self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/puzzles/stack/reverse_string/test_reverse_string.py b/puzzles/stack/reverse_string/test_reverse_string.py index 0b2c9084..4e6bc6f0 100644 --- a/puzzles/stack/reverse_string/test_reverse_string.py +++ b/puzzles/stack/reverse_string/test_reverse_string.py @@ -10,5 +10,5 @@ def test_one(self): self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/pystrings/anagram/__init__.py b/pystrings/anagram/__init__.py index e9d11030..41a9f667 100755 --- a/pystrings/anagram/__init__.py +++ b/pystrings/anagram/__init__.py @@ -83,7 +83,6 @@ def detect_anagrams(self, word, word_list): res.append(x) return res - def anagram_count(self, parent, child): """ Counts the number of times the anagram of a child string appears in a parent string diff --git a/pystrings/anagram/group_anagrams/__init__.py b/pystrings/anagram/group_anagrams/__init__.py index ec776dfc..1a58fbda 100644 --- a/pystrings/anagram/group_anagrams/__init__.py +++ b/pystrings/anagram/group_anagrams/__init__.py @@ -21,6 +21,7 @@ def group_anagrams_naive(strs: List[str]) -> List[List[str]]: return list(word_map.values()) + def group_anagrams(strs: List[str]) -> List[List[str]]: """ Groups a list of strings by their anagrams. @@ -55,12 +56,12 @@ def group_anagrams(strs: List[str]) -> List[List[str]]: Returns: List[List[str]]: A list of lists, where each inner list contains strings that are anagrams of each other """ - word_map: Dict[Tuple[int,...], List[str]] = defaultdict(list) + word_map: Dict[Tuple[int, ...], List[str]] = defaultdict(list) # traversing the list of strings takes O(n) time where n is the number of strings in this list for word in strs: count = [0] * 26 for char in word.lower(): - index = ord(char) - ord('a') + index = ord(char) - ord("a") count[index] += 1 key = tuple(count) diff --git a/pystrings/anagram/group_anagrams/test_group_anagrams.py b/pystrings/anagram/group_anagrams/test_group_anagrams.py index 269ae2d6..bdc0ea07 100644 --- a/pystrings/anagram/group_anagrams/test_group_anagrams.py +++ b/pystrings/anagram/group_anagrams/test_group_anagrams.py @@ -4,26 +4,70 @@ class GroupAnagramsTestCase(unittest.TestCase): - @parameterized.expand([ - ("test_1", ["eat", "beat", "neat", "tea"], [["eat", "tea"], ["beat"], ["neat"]]), - ("test_2", ["duel", "dule", "speed", "spede", "deul", "cars"], [["duel", "dule", "deul"], ["speed", "spede"], ["cars"]]), - ("test_3", ["eat","tea","tan","ate","nat","bat"], [["eat","tea","ate"],["tan","nat"],["bat"]]), - ("test_4", ["word","sword","drow","rowd","iced","dice"], [["word","drow","rowd"],["sword"],["iced","dice"]]), - ("test_5", ["eat","drink","sleep","repeat"], [["eat"],["drink"],["sleep"],["repeat"]]), - ("test_6", ["hello","ohlle","dark"], [["hello","ohlle"],["dark"]]) - ]) + @parameterized.expand( + [ + ( + "test_1", + ["eat", "beat", "neat", "tea"], + [["eat", "tea"], ["beat"], ["neat"]], + ), + ( + "test_2", + ["duel", "dule", "speed", "spede", "deul", "cars"], + [["duel", "dule", "deul"], ["speed", "spede"], ["cars"]], + ), + ( + "test_3", + ["eat", "tea", "tan", "ate", "nat", "bat"], + [["eat", "tea", "ate"], ["tan", "nat"], ["bat"]], + ), + ( + "test_4", + ["word", "sword", "drow", "rowd", "iced", "dice"], + [["word", "drow", "rowd"], ["sword"], ["iced", "dice"]], + ), + ( + "test_5", + ["eat", "drink", "sleep", "repeat"], + [["eat"], ["drink"], ["sleep"], ["repeat"]], + ), + ("test_6", ["hello", "ohlle", "dark"], [["hello", "ohlle"], ["dark"]]), + ] + ) def test1(self, _, strs, expected): actual = group_anagrams(strs) self.assertEqual(actual, expected) - @parameterized.expand([ - ("test_1", ["eat", "beat", "neat", "tea"], [["eat", "tea"], ["beat"], ["neat"]]), - ("test_2", ["duel", "dule", "speed", "spede", "deul", "cars"], [["duel", "dule", "deul"], ["speed", "spede"], ["cars"]]), - ("test_3", ["eat","tea","tan","ate","nat","bat"], [["eat","tea","ate"],["tan","nat"],["bat"]]), - ("test_4", ["word","sword","drow","rowd","iced","dice"], [["word","drow","rowd"],["sword"],["iced","dice"]]), - ("test_5", ["eat","drink","sleep","repeat"], [["eat"],["drink"],["sleep"],["repeat"]]), - ("test_6", ["hello","ohlle","dark"], [["hello","ohlle"],["dark"]]) - ]) + @parameterized.expand( + [ + ( + "test_1", + ["eat", "beat", "neat", "tea"], + [["eat", "tea"], ["beat"], ["neat"]], + ), + ( + "test_2", + ["duel", "dule", "speed", "spede", "deul", "cars"], + [["duel", "dule", "deul"], ["speed", "spede"], ["cars"]], + ), + ( + "test_3", + ["eat", "tea", "tan", "ate", "nat", "bat"], + [["eat", "tea", "ate"], ["tan", "nat"], ["bat"]], + ), + ( + "test_4", + ["word", "sword", "drow", "rowd", "iced", "dice"], + [["word", "drow", "rowd"], ["sword"], ["iced", "dice"]], + ), + ( + "test_5", + ["eat", "drink", "sleep", "repeat"], + [["eat"], ["drink"], ["sleep"], ["repeat"]], + ), + ("test_6", ["hello", "ohlle", "dark"], [["hello", "ohlle"], ["dark"]]), + ] + ) def test2(self, _, strs, expected): actual = group_anagrams_naive(strs) self.assertEqual(actual, expected) @@ -41,29 +85,29 @@ def test_2(self): self.assertEqual(expected, actual) def test_3(self): - strs = ["eat","tea","tan","ate","nat","bat"] - expected = [["eat","tea","ate"],["tan","nat"],["bat"]] + strs = ["eat", "tea", "tan", "ate", "nat", "bat"] + expected = [["eat", "tea", "ate"], ["tan", "nat"], ["bat"]] actual = group_anagrams(strs) self.assertEqual(expected, actual) def test_4(self): - strs = ["word","sword","drow","rowd","iced","dice"] - expected = [["word","drow","rowd"],["sword"],["iced","dice"]] + strs = ["word", "sword", "drow", "rowd", "iced", "dice"] + expected = [["word", "drow", "rowd"], ["sword"], ["iced", "dice"]] actual = group_anagrams(strs) self.assertEqual(expected, actual) def test_5(self): - strs = ["eat","drink","sleep","repeat"] - expected = [["eat"],["drink"],["sleep"],["repeat"]] + strs = ["eat", "drink", "sleep", "repeat"] + expected = [["eat"], ["drink"], ["sleep"], ["repeat"]] actual = group_anagrams(strs) self.assertEqual(expected, actual) def test_6(self): - strs = ["hello","ohlle","dark"] - expected = [["hello","ohlle"],["dark"]] + strs = ["hello", "ohlle", "dark"] + expected = [["hello", "ohlle"], ["dark"]] actual = group_anagrams(strs) self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/pystrings/count_consonants/__init__.py b/pystrings/count_consonants/__init__.py index e40e5560..f006b9f1 100644 --- a/pystrings/count_consonants/__init__.py +++ b/pystrings/count_consonants/__init__.py @@ -1,14 +1,16 @@ vowels = "aeiou" + def count_consonants_iterative(input_str: str) -> int: consonant_count = 0 for char in input_str: if char.lower() not in vowels and char.isalpha(): - consonant_count+=1 + consonant_count += 1 return consonant_count + def count_consonants_recursive(input_str: str) -> int: if input_str == "": return 0 diff --git a/pystrings/count_consonants/test_count_consonants.py b/pystrings/count_consonants/test_count_consonants.py index 28e99efe..43034143 100644 --- a/pystrings/count_consonants/test_count_consonants.py +++ b/pystrings/count_consonants/test_count_consonants.py @@ -1,6 +1,9 @@ import unittest -from pystrings.count_consonants import count_consonants_iterative, count_consonants_recursive +from pystrings.count_consonants import ( + count_consonants_iterative, + count_consonants_recursive, +) class CountConsonantsTestCases(unittest.TestCase): @@ -19,5 +22,5 @@ def test_1_recursive(self): self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/pystrings/inttostr/__init__.py b/pystrings/inttostr/__init__.py index e99f9ee6..dfd3b2ca 100644 --- a/pystrings/inttostr/__init__.py +++ b/pystrings/inttostr/__init__.py @@ -22,7 +22,7 @@ def int_to_str(input_int: int) -> str: # if the input integer is 0, then simply append '0' to the output result if input_int == 0: - output_str.append('0') + output_str.append("0") else: # if not, then the last digit of the input integer is extracted using the % operator. e.g. 12 % 10 = 2, 17%10=7 # Taking the modulus of a number with 10, always gets the last digit of that number. @@ -33,7 +33,7 @@ def int_to_str(input_int: int) -> str: # This repeats until the input integer is less than or equal to 0 while input_int > 0: last_digit = input_int % 10 - unicode = ord('0') + last_digit + unicode = ord("0") + last_digit character = chr(unicode) output_str.append(character) input_int //= 10 @@ -42,10 +42,10 @@ def int_to_str(input_int: int) -> str: output_str = output_str[::-1] # join the elements together - result = ''.join(output_str) + result = "".join(output_str) # deal with the sign. Add - if it was a negative integer or simply return the result if it was a positive integer. if is_negative: - return '-' + result + return "-" + result else: return result diff --git a/pystrings/inttostr/test_int_to_str.py b/pystrings/inttostr/test_int_to_str.py index 13be9bd5..5ccec699 100644 --- a/pystrings/inttostr/test_int_to_str.py +++ b/pystrings/inttostr/test_int_to_str.py @@ -32,5 +32,5 @@ def test_4(self): self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/pystrings/is_unique/test_is_unique.py b/pystrings/is_unique/test_is_unique.py index 3d7f9c91..34644acf 100644 --- a/pystrings/is_unique/test_is_unique.py +++ b/pystrings/is_unique/test_is_unique.py @@ -3,7 +3,6 @@ class IsUniqueTestCases(unittest.TestCase): - def test_1(self): """should return true for abCDefGh""" input_string = "abCDefGh" @@ -38,8 +37,10 @@ def test_6(self): """should return True for hi""" input_string = "hi" actual = is_unique(input_string) - self.assertTrue(actual,) + self.assertTrue( + actual, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/pystrings/look_and_say_sequence/__init__.py b/pystrings/look_and_say_sequence/__init__.py index 5d4e7726..0748c9a6 100644 --- a/pystrings/look_and_say_sequence/__init__.py +++ b/pystrings/look_and_say_sequence/__init__.py @@ -27,7 +27,7 @@ def look_and_say_sequence(sequence: str) -> str: # count is reset to one to keep track of the current count of the sequence count = 1 - while i + 1 < len(sequence) and sequence[i] == sequence[i+1]: + while i + 1 < len(sequence) and sequence[i] == sequence[i + 1]: # here we keep track of consecutive similar characters and increase their count if we encounter them. i += 1 diff --git a/pystrings/look_and_say_sequence/test_look_and_say_sequence.py b/pystrings/look_and_say_sequence/test_look_and_say_sequence.py index d3a02365..baacac09 100644 --- a/pystrings/look_and_say_sequence/test_look_and_say_sequence.py +++ b/pystrings/look_and_say_sequence/test_look_and_say_sequence.py @@ -25,5 +25,5 @@ def test_3(self): self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/pystrings/palindrome/permutation_palindrome/test_permutation_palindrome.py b/pystrings/palindrome/permutation_palindrome/test_permutation_palindrome.py index 5d9a01b1..e5259f1b 100644 --- a/pystrings/palindrome/permutation_palindrome/test_permutation_palindrome.py +++ b/pystrings/palindrome/permutation_palindrome/test_permutation_palindrome.py @@ -42,5 +42,5 @@ def test_3(self): self.assertTrue(actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/pystrings/permutation/__init__.py b/pystrings/permutation/__init__.py index 7eb5d24c..08ef9d26 100644 --- a/pystrings/permutation/__init__.py +++ b/pystrings/permutation/__init__.py @@ -36,6 +36,7 @@ def check_permutation_with_sorting(input_str_1: str, input_str_2: str) -> bool: return True + def check_permutation_with_map(input_str_1: str, input_str_2: str) -> bool: """ Check if two strings are permutations of each other. diff --git a/pystrings/permutation/test_check_permutation.py b/pystrings/permutation/test_check_permutation.py index 6f8c4549..e90b2db3 100644 --- a/pystrings/permutation/test_check_permutation.py +++ b/pystrings/permutation/test_check_permutation.py @@ -33,5 +33,6 @@ def test_2(self): actual = check_permutation_with_map(word_1, word_2) self.assertFalse(actual) -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() diff --git a/pystrings/spreadsheet_encoding/__init__.py b/pystrings/spreadsheet_encoding/__init__.py index cd60c288..52f9c692 100644 --- a/pystrings/spreadsheet_encoding/__init__.py +++ b/pystrings/spreadsheet_encoding/__init__.py @@ -24,7 +24,7 @@ def spreadsheet_encode_column(column_id: str) -> int: # relative difference from the result given by ord & from the representation we require for base 26 system # Now we know that ord('A') equals 65. So if we find the Unicode code point using ord() of a character, # subtract ord('A') from it, and then add 1 to it, we’ll get the representation we want for the base 26 system - num += 26**count * (ord(char) - ord('A') + 1) + num += 26**count * (ord(char) - ord("A") + 1) # count is decremented by 1 as the power of the base decrements by 1 from the digits from left to right count -= 1 diff --git a/pystrings/spreadsheet_encoding/test_spreadsheet_encode.py b/pystrings/spreadsheet_encoding/test_spreadsheet_encode.py index 477111a9..c95a9fa0 100644 --- a/pystrings/spreadsheet_encoding/test_spreadsheet_encode.py +++ b/pystrings/spreadsheet_encoding/test_spreadsheet_encode.py @@ -8,8 +8,8 @@ def test_zz(self): column_name = "ZZ" expected = 702 actual = spreadsheet_encode_column(column_name) - self.assertEqual(expected,actual) + self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/pystrings/string_length/__init__.py b/pystrings/string_length/__init__.py index 45b3d81d..2e524fa9 100644 --- a/pystrings/string_length/__init__.py +++ b/pystrings/string_length/__init__.py @@ -12,6 +12,7 @@ def iterative_string_len(input_str: str) -> int: count += 1 return count + def recursive_string_len(input_str: str) -> int: """ Calculates a string's length using a recursive approach @@ -23,4 +24,4 @@ def recursive_string_len(input_str: str) -> int: """ if input_str == "": return 0 - return 1 + recursive_string_len(input_str[1:]) \ No newline at end of file + return 1 + recursive_string_len(input_str[1:]) diff --git a/pystrings/string_length/test_string_length.py b/pystrings/string_length/test_string_length.py index 36a898f6..2e789342 100644 --- a/pystrings/string_length/test_string_length.py +++ b/pystrings/string_length/test_string_length.py @@ -18,5 +18,5 @@ def test_1_recursive(self): self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/pystrings/strtoint/__init__.py b/pystrings/strtoint/__init__.py index df391c58..0f760b14 100644 --- a/pystrings/strtoint/__init__.py +++ b/pystrings/strtoint/__init__.py @@ -8,7 +8,7 @@ def str_to_int(input_str: str) -> int: """ output_int = 0 - if input_str[0] == '-': + if input_str[0] == "-": is_negative = True else: is_negative = False @@ -18,17 +18,18 @@ def str_to_int(input_str: str) -> int: str_to_convert = input_str[1:] if is_negative else input_str for index, char in enumerate(str_to_convert): - unicode = ord(char) - ord('0') + unicode = ord(char) - ord("0") exponent = l - (index + 1) number = unicode * 10**exponent output_int += number - return output_int *-1 if is_negative else output_int + return output_int * -1 if is_negative else output_int + def str_to_int_v2(input_str: str) -> int: output_int = 0 - if input_str[0] == '-': + if input_str[0] == "-": start_idx = 1 is_negative = True else: @@ -36,8 +37,8 @@ def str_to_int_v2(input_str: str) -> int: is_negative = False for i in range(start_idx, len(input_str)): - place = 10**(len(input_str) - (i+1)) - digit = ord(input_str[i]) - ord('0') + place = 10 ** (len(input_str) - (i + 1)) + digit = ord(input_str[i]) - ord("0") output_int += place * digit if is_negative: diff --git a/pystrings/strtoint/test_string_to_int.py b/pystrings/strtoint/test_string_to_int.py index 5fce3540..42ea6986 100644 --- a/pystrings/strtoint/test_string_to_int.py +++ b/pystrings/strtoint/test_string_to_int.py @@ -104,5 +104,5 @@ def test_7(self): self.assertEqual(expected, actual) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main()