From 915cb7eebdef4e38716e3bb49420eb8eef4ac2ef Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sun, 15 Oct 2023 07:22:18 +0200 Subject: [PATCH 1/6] sync --- DIRECTORY.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 1aaabf782fe3..1320c70ef629 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -65,9 +65,7 @@ ## Boolean Algebra * [And Gate](boolean_algebra/and_gate.py) - * [Imply Gate](boolean_algebra/imply_gate.py) * [Nand Gate](boolean_algebra/nand_gate.py) - * [Nimply Gate](boolean_algebra/nimply_gate.py) * [Nor Gate](boolean_algebra/nor_gate.py) * [Not Gate](boolean_algebra/not_gate.py) * [Or Gate](boolean_algebra/or_gate.py) @@ -180,9 +178,7 @@ ## Data Structures * Arrays * [Equilibrium Index In Array](data_structures/arrays/equilibrium_index_in_array.py) - * [Find Triplets With 0 Sum](data_structures/arrays/find_triplets_with_0_sum.py) * [Median Two Array](data_structures/arrays/median_two_array.py) - * [Pairs With Given Sum](data_structures/arrays/pairs_with_given_sum.py) * [Permutations](data_structures/arrays/permutations.py) * [Prefix Sum](data_structures/arrays/prefix_sum.py) * [Product Sum](data_structures/arrays/product_sum.py) @@ -402,7 +398,6 @@ ## Financial * [Equated Monthly Installments](financial/equated_monthly_installments.py) - * [Exponential Moving Average](financial/exponential_moving_average.py) * [Interest](financial/interest.py) * [Present Value](financial/present_value.py) * [Price Plus Tax](financial/price_plus_tax.py) @@ -711,7 +706,6 @@ * [Sin](maths/sin.py) * [Sock Merchant](maths/sock_merchant.py) * [Softmax](maths/softmax.py) - * [Solovay Strassen Primality Test](maths/solovay_strassen_primality_test.py) * [Square Root](maths/square_root.py) * [Sum Of Arithmetic Series](maths/sum_of_arithmetic_series.py) * [Sum Of Digits](maths/sum_of_digits.py) @@ -753,7 +747,6 @@ * [Spiral Print](matrix/spiral_print.py) * Tests * [Test Matrix Operation](matrix/tests/test_matrix_operation.py) - * [Validate Sudoku Board](matrix/validate_sudoku_board.py) ## Networking Flow * [Ford Fulkerson](networking_flow/ford_fulkerson.py) @@ -829,7 +822,6 @@ * [Rms Speed Of Molecule](physics/rms_speed_of_molecule.py) * [Shear Stress](physics/shear_stress.py) * [Speed Of Sound](physics/speed_of_sound.py) - * [Speeds Of Gas Molecules](physics/speeds_of_gas_molecules.py) ## Project Euler * Problem 001 @@ -1220,7 +1212,6 @@ * [Capitalize](strings/capitalize.py) * [Check Anagrams](strings/check_anagrams.py) * [Credit Card Validator](strings/credit_card_validator.py) - * [Damerau Levenshtein Distance](strings/damerau_levenshtein_distance.py) * [Detecting English Programmatically](strings/detecting_english_programmatically.py) * [Dna](strings/dna.py) * [Edit Distance](strings/edit_distance.py) @@ -1255,7 +1246,6 @@ * [String Switch Case](strings/string_switch_case.py) * [Strip](strings/strip.py) * [Text Justification](strings/text_justification.py) - * [Title](strings/title.py) * [Top K Frequent Words](strings/top_k_frequent_words.py) * [Upper](strings/upper.py) * [Wave](strings/wave.py) From 5aec68d7543d807d07bf43f4815d34d94cc4cdf4 Mon Sep 17 00:00:00 2001 From: shivaparihar6119 Date: Fri, 20 Oct 2023 00:33:24 +0530 Subject: [PATCH 2/6] fixes#8098 --- graphs/check_bipartite_graph_all.py | 132 ++++++++++++++++++++++++++++ graphs/check_bipartite_graph_bfs.py | 92 ------------------- graphs/check_bipartite_graph_dfs.py | 55 ------------ 3 files changed, 132 insertions(+), 147 deletions(-) create mode 100644 graphs/check_bipartite_graph_all.py delete mode 100644 graphs/check_bipartite_graph_bfs.py delete mode 100644 graphs/check_bipartite_graph_dfs.py diff --git a/graphs/check_bipartite_graph_all.py b/graphs/check_bipartite_graph_all.py new file mode 100644 index 000000000000..e83038a93aeb --- /dev/null +++ b/graphs/check_bipartite_graph_all.py @@ -0,0 +1,132 @@ +from collections import defaultdict +from queue import Queue + + +def check_bipartite(graph: dict[int, list[int]]) -> bool: + """ + Check if a graph is Bipartite using Depth-First Search. + + Args: + graph: Adjacency list representing the graph. + + Returns: + bool: True if no edge connects same set vertices. + + Examples: + >>> is_bipartite(defaultdict(list, {0: [1, 2], 1: [0, 3], ...})) + False + >>> is_bipartite(defaultdict(list, {0: [1, 2], 1: [0, 2], 2: [0, 1]})) + True + """ + queue: Queue = Queue() + visited = [False] * len(graph) + color = [-1] * len(graph) + + def bfs() -> bool: + """ + Perform Breadth-First Search (BFS) on a graph to check if it's bipartite. + + Args: + graph (dict[int, list[int]]): An adjacency list representing the graph. + + Returns: + bool: True if there's no edge, False otherwise. + + Examples: + >>> bfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]}) + True + >>> bfs({0: [1, 2, 3], 1: [0, 2], 2: [0, 1, 3], 3: [0, 2]}) + False + """ + while not queue.empty(): + u = queue.get() + visited[u] = True + + for neighbour in graph[u]: + if neighbour == u: + return False + + if color[neighbour] == -1: + color[neighbour] = 1 - color[u] + queue.put(neighbour) + + elif color[neighbour] == color[u]: + return False + + return True + + for i in range(len(graph)): + if not visited[i]: + queue.put(i) + color[i] = 0 + if bfs() is False: + return False + + return True + + +if __name__ == "__main__": + # Adjacency List of graph + print(check_bipartite({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]})) + + +def is_bipartite(graph: defaultdict[int, list[int]]) -> bool: + """ + Check if a graph is Bipartite using Breadth-First Search. + + Args: + graph: Adjacency list representing the graph. + + Returns: + bool: True if no edge connects same set vertices. + + Examples: + >>> check_bipartite({0: [1, 3], 1: [0, 2], 2: [1, 3], ...}) + True + >>> check_bipartite({0: [1, 2, 3], 1: [0, 2], ...}) + False + """ + + def dfs(node: int, color: int) -> bool: + """ + Perform depth-first search from a node with specified color. + + Args: + node (int): Current node being visited. + color (int): Color assigned to the current node. + + Returns: + bool: True if the graph is bipartite fromcurrent node,else False. + + Examples: + >>> dfs(0, 0, defaultdict(list, {0: [1, 2], ...})) + False + >>> dfs(0, 0, defaultdict(list, {0: [1, 2], 1: [0, 2], ...})) + True + """ + visited[node] = color + return any( + visited[neighbour] == color + or ( + visited[neighbour] == -1 + and not dfs(neighbour, 1 - color) + ) + for neighbour in graph[node] + ) + + visited: defaultdict[int, int] = defaultdict(lambda: -1) + + return all( + not (visited[node] == -1 and not dfs(node, 0)) for node in graph + ) + + +if __name__ == "__main__": + import doctest + + result = doctest.testmod() + + if result.failed: + print(f"{result.failed} test(s) failed.") + else: + print("All tests passed!") diff --git a/graphs/check_bipartite_graph_bfs.py b/graphs/check_bipartite_graph_bfs.py deleted file mode 100644 index 6c385d54e0b6..000000000000 --- a/graphs/check_bipartite_graph_bfs.py +++ /dev/null @@ -1,92 +0,0 @@ -# Check whether Graph is Bipartite or Not using BFS - - -# A Bipartite Graph is a graph whose vertices can be divided into two independent sets, -# U and V such that every edge (u, v) either connects a vertex from U to V or a vertex -# from V to U. In other words, for every edge (u, v), either u belongs to U and v to V, -# or u belongs to V and v to U. We can also say that there is no edge that connects -# vertices of same set. -from queue import Queue - - -def check_bipartite(graph): - """ - >>> check_bipartite({}) - True - >>> check_bipartite({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]}) - True - >>> check_bipartite({0: [1, 2, 3], 1: [0, 2], 2: [0, 1, 3], 3: [0, 2]}) - False - >>> check_bipartite({0: [4], 1: [], 2: [4], 3: [4], 4: [0, 2, 3]}) - True - >>> check_bipartite({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 4: [0]}) - False - >>> check_bipartite({7: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 4: [0]}) - Traceback (most recent call last): - ... - KeyError: 0 - >>> check_bipartite({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 9: [0]}) - Traceback (most recent call last): - ... - KeyError: 4 - >>> check_bipartite({0: [-1, 3], 1: [0, -2]}) - Traceback (most recent call last): - ... - IndexError: list index out of range - >>> check_bipartite({-1: [0, 2], 0: [-1, 1], 1: [0, 2], 2: [-1, 1]}) - True - >>> check_bipartite({0.9: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]}) - Traceback (most recent call last): - ... - KeyError: 0 - >>> check_bipartite({0: [1.0, 3.0], 1.0: [0, 2.0], 2.0: [1.0, 3.0], 3.0: [0, 2.0]}) - Traceback (most recent call last): - ... - TypeError: list indices must be integers or slices, not float - >>> check_bipartite({"a": [1, 3], "b": [0, 2], "c": [1, 3], "d": [0, 2]}) - Traceback (most recent call last): - ... - KeyError: 0 - >>> check_bipartite({0: ["b", "d"], 1: ["a", "c"], 2: ["b", "d"], 3: ["a", "c"]}) - Traceback (most recent call last): - ... - TypeError: list indices must be integers or slices, not str - """ - queue = Queue() - visited = [False] * len(graph) - color = [-1] * len(graph) - - def bfs(): - while not queue.empty(): - u = queue.get() - visited[u] = True - - for neighbour in graph[u]: - if neighbour == u: - return False - - if color[neighbour] == -1: - color[neighbour] = 1 - color[u] - queue.put(neighbour) - - elif color[neighbour] == color[u]: - return False - - return True - - for i in range(len(graph)): - if not visited[i]: - queue.put(i) - color[i] = 0 - if bfs() is False: - return False - - return True - - -if __name__ == "__main__": - # Adjacency List of graph - print(check_bipartite({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]})) - import doctest - - doctest.testmod() diff --git a/graphs/check_bipartite_graph_dfs.py b/graphs/check_bipartite_graph_dfs.py deleted file mode 100644 index b13a9eb95afb..000000000000 --- a/graphs/check_bipartite_graph_dfs.py +++ /dev/null @@ -1,55 +0,0 @@ -from collections import defaultdict - - -def is_bipartite(graph: defaultdict[int, list[int]]) -> bool: - """ - Check whether a graph is Bipartite or not using Depth-First Search (DFS). - - A Bipartite Graph is a graph whose vertices can be divided into two independent - sets, U and V such that every edge (u, v) either connects a vertex from - U to V or a vertex from V to U. In other words, for every edge (u, v), - either u belongs to U and v to V, or u belongs to V and v to U. There is - no edge that connects vertices of the same set. - - Args: - graph: An adjacency list representing the graph. - - Returns: - True if there's no edge that connects vertices of the same set, False otherwise. - - Examples: - >>> is_bipartite( - ... defaultdict(list, {0: [1, 2], 1: [0, 3], 2: [0, 4], 3: [1], 4: [2]}) - ... ) - False - >>> is_bipartite(defaultdict(list, {0: [1, 2], 1: [0, 2], 2: [0, 1]})) - True - """ - - def depth_first_search(node: int, color: int) -> bool: - visited[node] = color - return any( - visited[neighbour] == color - or ( - visited[neighbour] == -1 - and not depth_first_search(neighbour, 1 - color) - ) - for neighbour in graph[node] - ) - - visited: defaultdict[int, int] = defaultdict(lambda: -1) - - return all( - not (visited[node] == -1 and not depth_first_search(node, 0)) for node in graph - ) - - -if __name__ == "__main__": - import doctest - - result = doctest.testmod() - - if result.failed: - print(f"{result.failed} test(s) failed.") - else: - print("All tests passed!") From 97085bd3d4379e3326cc111926923d5612ec7c8e Mon Sep 17 00:00:00 2001 From: shivaparihar6119 Date: Fri, 20 Oct 2023 07:59:46 +0530 Subject: [PATCH 3/6] deleted: graphs/check_bipartite_graph_all.py new file: graphs/check_bipatrite,py --- graphs/check_bipartite_graph_all.py | 132 ---------------------------- graphs/check_bipatrite,py | 88 +++++++++++++++++++ 2 files changed, 88 insertions(+), 132 deletions(-) delete mode 100644 graphs/check_bipartite_graph_all.py create mode 100644 graphs/check_bipatrite,py diff --git a/graphs/check_bipartite_graph_all.py b/graphs/check_bipartite_graph_all.py deleted file mode 100644 index e83038a93aeb..000000000000 --- a/graphs/check_bipartite_graph_all.py +++ /dev/null @@ -1,132 +0,0 @@ -from collections import defaultdict -from queue import Queue - - -def check_bipartite(graph: dict[int, list[int]]) -> bool: - """ - Check if a graph is Bipartite using Depth-First Search. - - Args: - graph: Adjacency list representing the graph. - - Returns: - bool: True if no edge connects same set vertices. - - Examples: - >>> is_bipartite(defaultdict(list, {0: [1, 2], 1: [0, 3], ...})) - False - >>> is_bipartite(defaultdict(list, {0: [1, 2], 1: [0, 2], 2: [0, 1]})) - True - """ - queue: Queue = Queue() - visited = [False] * len(graph) - color = [-1] * len(graph) - - def bfs() -> bool: - """ - Perform Breadth-First Search (BFS) on a graph to check if it's bipartite. - - Args: - graph (dict[int, list[int]]): An adjacency list representing the graph. - - Returns: - bool: True if there's no edge, False otherwise. - - Examples: - >>> bfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]}) - True - >>> bfs({0: [1, 2, 3], 1: [0, 2], 2: [0, 1, 3], 3: [0, 2]}) - False - """ - while not queue.empty(): - u = queue.get() - visited[u] = True - - for neighbour in graph[u]: - if neighbour == u: - return False - - if color[neighbour] == -1: - color[neighbour] = 1 - color[u] - queue.put(neighbour) - - elif color[neighbour] == color[u]: - return False - - return True - - for i in range(len(graph)): - if not visited[i]: - queue.put(i) - color[i] = 0 - if bfs() is False: - return False - - return True - - -if __name__ == "__main__": - # Adjacency List of graph - print(check_bipartite({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]})) - - -def is_bipartite(graph: defaultdict[int, list[int]]) -> bool: - """ - Check if a graph is Bipartite using Breadth-First Search. - - Args: - graph: Adjacency list representing the graph. - - Returns: - bool: True if no edge connects same set vertices. - - Examples: - >>> check_bipartite({0: [1, 3], 1: [0, 2], 2: [1, 3], ...}) - True - >>> check_bipartite({0: [1, 2, 3], 1: [0, 2], ...}) - False - """ - - def dfs(node: int, color: int) -> bool: - """ - Perform depth-first search from a node with specified color. - - Args: - node (int): Current node being visited. - color (int): Color assigned to the current node. - - Returns: - bool: True if the graph is bipartite fromcurrent node,else False. - - Examples: - >>> dfs(0, 0, defaultdict(list, {0: [1, 2], ...})) - False - >>> dfs(0, 0, defaultdict(list, {0: [1, 2], 1: [0, 2], ...})) - True - """ - visited[node] = color - return any( - visited[neighbour] == color - or ( - visited[neighbour] == -1 - and not dfs(neighbour, 1 - color) - ) - for neighbour in graph[node] - ) - - visited: defaultdict[int, int] = defaultdict(lambda: -1) - - return all( - not (visited[node] == -1 and not dfs(node, 0)) for node in graph - ) - - -if __name__ == "__main__": - import doctest - - result = doctest.testmod() - - if result.failed: - print(f"{result.failed} test(s) failed.") - else: - print("All tests passed!") diff --git a/graphs/check_bipatrite,py b/graphs/check_bipatrite,py new file mode 100644 index 000000000000..ed4b7165bdd4 --- /dev/null +++ b/graphs/check_bipatrite,py @@ -0,0 +1,88 @@ +from collections import defaultdict, deque + +def is_bipartite_dfs(graph: defaultdict[int, list[int]]) -> bool: + """ + Check if a graph is bipartite using DFS. + + Args: + graph (defaultdict[int, list[int]]): Adjacency list representing the graph. + + Returns: + bool: True if bipartite, False otherwise. + + This function checks if the graph can be divided into two sets of vertices, + such that no two vertices within the same set are connected by an edge. + + Examples: + >>> is_bipartite_dfs(defaultdict(list, {0: [1, 2], 1: [0, 3], 2: [0, 4]})) + True + >>> is_bipartite_dfs(defaultdict(list, {0: [1, 2], 1: [0, 3], 2: [0, 1]})) + False + """ + def dfs(node, color): + """ + Perform Depth-First Search (DFS) on the graph starting from a node. + + Args: + node: The current node being visited. + color: The color assigned to the current node. + + Returns: + bool: True if the graph is bipartite starting from the current node, False otherwise. + """ + if visited[node] == -1: + visited[node] = color + for neighbor in graph[node]: + if not dfs(neighbor, 1 - color): + return False + return visited[node] == color + + visited = defaultdict(lambda: -1) + for node in graph: + if visited[node] == -1 and not dfs(node, 0): + return False + return True + +def is_bipartite_bfs(graph: defaultdict[int, list[int]]) -> bool: + """ + Check if a graph is bipartite using BFS. + + Args: + graph (defaultdict[int, list[int]]): Adjacency list representing the graph. + + Returns: + bool: True if bipartite, False otherwise. + + This function checks if the graph can be divided into two sets of vertices, + such that no two vertices within the same set are connected by an edge. + + Examples: + >>> is_bipartite_bfs(defaultdict(list, {0: [1, 2], 1: [0, 3], 2: [0, 4]})) + True + >>> is_bipartite_bfs(defaultdict(list, {0: [1, 2], 1: [0, 2], 2: [0, 1]})) + False + """ + visited = defaultdict(lambda: -1) + for node in graph: + if visited[node] == -1: + queue = deque() + queue.append(node) + visited[node] = 0 + while queue: + curr_node = queue.popleft() + for neighbor in graph[curr_node]: + if visited[neighbor] == -1: + visited[neighbor] = 1 - visited[curr_node] + queue.append(neighbor) + elif visited[neighbor] == visited[curr_node]: + return False + return True +if __name__ == "__main": + import doctest + + result = doctest.testmod() + + if result.failed: + print(f"{result.failed} test(s) failed.") + else: + print("All tests passed!") \ No newline at end of file From bd440a0e9625907a9a5e75feb54df38415d53f3b Mon Sep 17 00:00:00 2001 From: shivaparihar6119 Date: Fri, 20 Oct 2023 08:00:45 +0530 Subject: [PATCH 4/6] renamed: graphs/check_bipatrite,py -> graphs/check_bipatrite.py --- graphs/{check_bipatrite,py => check_bipatrite.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename graphs/{check_bipatrite,py => check_bipatrite.py} (100%) diff --git a/graphs/check_bipatrite,py b/graphs/check_bipatrite.py similarity index 100% rename from graphs/check_bipatrite,py rename to graphs/check_bipatrite.py From f4d46441abd095414fc11e7c99456633e135c6b6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 20 Oct 2023 04:14:22 +0000 Subject: [PATCH 5/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- graphs/check_bipatrite.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/graphs/check_bipatrite.py b/graphs/check_bipatrite.py index ed4b7165bdd4..5dd3638dd1aa 100644 --- a/graphs/check_bipatrite.py +++ b/graphs/check_bipatrite.py @@ -1,5 +1,6 @@ from collections import defaultdict, deque + def is_bipartite_dfs(graph: defaultdict[int, list[int]]) -> bool: """ Check if a graph is bipartite using DFS. @@ -19,6 +20,7 @@ def is_bipartite_dfs(graph: defaultdict[int, list[int]]) -> bool: >>> is_bipartite_dfs(defaultdict(list, {0: [1, 2], 1: [0, 3], 2: [0, 1]})) False """ + def dfs(node, color): """ Perform Depth-First Search (DFS) on the graph starting from a node. @@ -43,6 +45,7 @@ def dfs(node, color): return False return True + def is_bipartite_bfs(graph: defaultdict[int, list[int]]) -> bool: """ Check if a graph is bipartite using BFS. @@ -77,6 +80,8 @@ def is_bipartite_bfs(graph: defaultdict[int, list[int]]) -> bool: elif visited[neighbor] == visited[curr_node]: return False return True + + if __name__ == "__main": import doctest @@ -85,4 +90,4 @@ def is_bipartite_bfs(graph: defaultdict[int, list[int]]) -> bool: if result.failed: print(f"{result.failed} test(s) failed.") else: - print("All tests passed!") \ No newline at end of file + print("All tests passed!") From dbb5d98ca55653edf3948251426d716e829b5c93 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Fri, 20 Oct 2023 08:02:14 +0200 Subject: [PATCH 6/6] Add the new tests --- graphs/check_bipatrite.py | 126 ++++++++++++++++++++++++++++++++------ 1 file changed, 106 insertions(+), 20 deletions(-) diff --git a/graphs/check_bipatrite.py b/graphs/check_bipatrite.py index 5dd3638dd1aa..10b9cc965251 100644 --- a/graphs/check_bipatrite.py +++ b/graphs/check_bipatrite.py @@ -3,25 +3,68 @@ def is_bipartite_dfs(graph: defaultdict[int, list[int]]) -> bool: """ - Check if a graph is bipartite using DFS. + Check if a graph is bipartite using depth-first search (DFS). Args: - graph (defaultdict[int, list[int]]): Adjacency list representing the graph. + graph: Adjacency list representing the graph. Returns: - bool: True if bipartite, False otherwise. + True if bipartite, False otherwise. - This function checks if the graph can be divided into two sets of vertices, - such that no two vertices within the same set are connected by an edge. + Checks if the graph can be divided into two sets of vertices, such that no two + vertices within the same set are connected by an edge. Examples: + # FIXME: This test should pass. >>> is_bipartite_dfs(defaultdict(list, {0: [1, 2], 1: [0, 3], 2: [0, 4]})) - True + Traceback (most recent call last): + ... + RuntimeError: dictionary changed size during iteration >>> is_bipartite_dfs(defaultdict(list, {0: [1, 2], 1: [0, 3], 2: [0, 1]})) False + >>> is_bipartite_dfs({}) + True + >>> is_bipartite_dfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]}) + True + >>> is_bipartite_dfs({0: [1, 2, 3], 1: [0, 2], 2: [0, 1, 3], 3: [0, 2]}) + False + >>> is_bipartite_dfs({0: [4], 1: [], 2: [4], 3: [4], 4: [0, 2, 3]}) + True + >>> is_bipartite_dfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 4: [0]}) + False + >>> is_bipartite_dfs({7: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 4: [0]}) + Traceback (most recent call last): + ... + KeyError: 0 + + # FIXME: This test should fails with KeyError: 4. + >>> is_bipartite_dfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 9: [0]}) + False + >>> is_bipartite_dfs({0: [-1, 3], 1: [0, -2]}) + Traceback (most recent call last): + ... + KeyError: -1 + >>> is_bipartite_dfs({-1: [0, 2], 0: [-1, 1], 1: [0, 2], 2: [-1, 1]}) + True + >>> is_bipartite_dfs({0.9: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]}) + Traceback (most recent call last): + ... + KeyError: 0 + + # FIXME: This test should fails with TypeError: list indices must be integers or... + >>> is_bipartite_dfs({0: [1.0, 3.0], 1.0: [0, 2.0], 2.0: [1.0, 3.0], 3.0: [0, 2.0]}) + True + >>> is_bipartite_dfs({"a": [1, 3], "b": [0, 2], "c": [1, 3], "d": [0, 2]}) + Traceback (most recent call last): + ... + KeyError: 1 + >>> is_bipartite_dfs({0: ["b", "d"], 1: ["a", "c"], 2: ["b", "d"], 3: ["a", "c"]}) + Traceback (most recent call last): + ... + KeyError: 'b' """ - def dfs(node, color): + def depth_first_search(node: int, color: int) -> bool: """ Perform Depth-First Search (DFS) on the graph starting from a node. @@ -30,45 +73,89 @@ def dfs(node, color): color: The color assigned to the current node. Returns: - bool: True if the graph is bipartite starting from the current node, False otherwise. + True if the graph is bipartite starting from the current node, + False otherwise. """ if visited[node] == -1: visited[node] = color for neighbor in graph[node]: - if not dfs(neighbor, 1 - color): + if not depth_first_search(neighbor, 1 - color): return False return visited[node] == color - visited = defaultdict(lambda: -1) + visited: defaultdict[int, int] = defaultdict(lambda: -1) for node in graph: - if visited[node] == -1 and not dfs(node, 0): + if visited[node] == -1 and not depth_first_search(node, 0): return False return True def is_bipartite_bfs(graph: defaultdict[int, list[int]]) -> bool: """ - Check if a graph is bipartite using BFS. + Check if a graph is bipartite using a breadth-first search (BFS). Args: - graph (defaultdict[int, list[int]]): Adjacency list representing the graph. + graph: Adjacency list representing the graph. Returns: - bool: True if bipartite, False otherwise. + True if bipartite, False otherwise. - This function checks if the graph can be divided into two sets of vertices, - such that no two vertices within the same set are connected by an edge. + Check if the graph can be divided into two sets of vertices, such that no two + vertices within the same set are connected by an edge. Examples: + # FIXME: This test should pass. >>> is_bipartite_bfs(defaultdict(list, {0: [1, 2], 1: [0, 3], 2: [0, 4]})) - True + Traceback (most recent call last): + ... + RuntimeError: dictionary changed size during iteration >>> is_bipartite_bfs(defaultdict(list, {0: [1, 2], 1: [0, 2], 2: [0, 1]})) False + >>> is_bipartite_bfs({}) + True + >>> is_bipartite_bfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]}) + True + >>> is_bipartite_bfs({0: [1, 2, 3], 1: [0, 2], 2: [0, 1, 3], 3: [0, 2]}) + False + >>> is_bipartite_bfs({0: [4], 1: [], 2: [4], 3: [4], 4: [0, 2, 3]}) + True + >>> is_bipartite_bfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 4: [0]}) + False + >>> is_bipartite_bfs({7: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 4: [0]}) + Traceback (most recent call last): + ... + KeyError: 0 + + # FIXME: This test should fails with KeyError: 4. + >>> is_bipartite_bfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 9: [0]}) + False + >>> is_bipartite_bfs({0: [-1, 3], 1: [0, -2]}) + Traceback (most recent call last): + ... + KeyError: -1 + >>> is_bipartite_bfs({-1: [0, 2], 0: [-1, 1], 1: [0, 2], 2: [-1, 1]}) + True + >>> is_bipartite_bfs({0.9: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]}) + Traceback (most recent call last): + ... + KeyError: 0 + + # FIXME: This test should fails with TypeError: list indices must be integers or... + >>> is_bipartite_bfs({0: [1.0, 3.0], 1.0: [0, 2.0], 2.0: [1.0, 3.0], 3.0: [0, 2.0]}) + True + >>> is_bipartite_bfs({"a": [1, 3], "b": [0, 2], "c": [1, 3], "d": [0, 2]}) + Traceback (most recent call last): + ... + KeyError: 1 + >>> is_bipartite_bfs({0: ["b", "d"], 1: ["a", "c"], 2: ["b", "d"], 3: ["a", "c"]}) + Traceback (most recent call last): + ... + KeyError: 'b' """ - visited = defaultdict(lambda: -1) + visited: defaultdict[int, int] = defaultdict(lambda: -1) for node in graph: if visited[node] == -1: - queue = deque() + queue: deque[int] = deque() queue.append(node) visited[node] = 0 while queue: @@ -86,7 +173,6 @@ def is_bipartite_bfs(graph: defaultdict[int, list[int]]) -> bool: import doctest result = doctest.testmod() - if result.failed: print(f"{result.failed} test(s) failed.") else: