def find_ladders(beginWord, endWord, wordList): """ :type beginWord: str :type endWord: str :type wordList: List[str] :rtype: List[List[str]] """ # ensure we add the beginWord to the graph graph_words = [beginWord] + wordList graph = Graph.from_same_length_word_list(graph_words) # to trace our path back when we find the target parent_of = defaultdict(lambda: []) depth = defaultdict(lambda: math.inf) depth[beginWord] = 0 queue = Queue() queue.enqueue(beginWord) success = False while (not queue.is_empty()): current = queue.dequeue() if (current == endWord): success = True for child in graph.get_neighbors(current): not_encountered_yet = depth[child] == math.inf already_encountered_at_same_depth = depth[ child] == depth[current] + 1 if (not_encountered_yet): depth[child] = depth[current] + 1 parent_of[child].append(current) queue.enqueue(child) elif (already_encountered_at_same_depth): parent_of[child].append(current) if success: all_paths = DoublyLinkedList() current_path = DoublyLinkedList() dfs(parent_of, endWord, all_paths, current_path) return all_paths.to_array_from_head() else: return []
def setup_method(self): self.graph = Graph() self.TestClass = None
class DepthFirstPathsTestCommon: def setup_method(self): self.graph = Graph() self.TestClass = None def build_default_graph(self): self.graph.add_edge(0, 1) self.graph.add_edge(0, 2) self.graph.add_edge(0, 5) self.graph.add_edge(1, 2) self.graph.add_edge(2, 3) self.graph.add_edge(2, 4) self.graph.add_edge(3, 4) self.graph.add_edge(3, 5) self.graph.add_edge(6, 7) self.graph.add_edge(6, 8) self.graph.add_edge(7, 8) def assert_has_path_to(self, paths, keys): for key in keys: assert paths.has_path_to(self.graph.vertex(key)) def assert_not_has_path_to(self, paths, keys): for key in keys: assert not paths.has_path_to(self.graph.vertex(key)) def assert_path(self, paths, to_vertex_key, expected_keys): vertices = paths.path_to(self.graph.vertex(to_vertex_key)) keys = [v.key for v in vertices] assert has_same_items(keys, expected_keys) def test_check_has_path(self): self.build_default_graph() paths = self.TestClass(self.graph, self.graph.vertex(0)) self.assert_has_path_to(paths, [0, 1, 2, 3, 4, 5]) self.assert_not_has_path_to(paths, [6, 7, 8]) paths = self.TestClass(self.graph, self.graph.vertex(7)) self.assert_has_path_to(paths, [6, 7, 8]) self.assert_not_has_path_to(paths, [0, 1, 2, 3, 4, 5]) def test_get_paths(self): self.build_default_graph() paths = self.TestClass(self.graph, self.graph.vertex(0)) self.assert_path(paths, 0, [0]) self.assert_path(paths, 1, [0, 1]) self.assert_path(paths, 2, [0, 1, 2]) self.assert_path(paths, 3, [0, 1, 2, 3]) self.assert_path(paths, 4, [0, 1, 2, 3, 4]) self.assert_path(paths, 5, [0, 1, 2, 3, 5]) self.assert_path(paths, 6, []) self.assert_path(paths, 7, []) self.assert_path(paths, 8, [])
def setup_method(self): self.graph = Graph()
class TestConnectedComponents: def setup_method(self): self.graph = Graph() def build_default_graph(self): self.graph.add_edge(0, 1) self.graph.add_edge(0, 2) self.graph.add_edge(0, 5) self.graph.add_edge(1, 2) self.graph.add_edge(2, 3) self.graph.add_edge(2, 4) self.graph.add_edge(3, 4) self.graph.add_edge(3, 5) self.graph.add_edge(6, 7) self.graph.add_edge(6, 8) self.graph.add_edge(7, 8) def test_find_connected_components(self): self.build_default_graph() cc = ConnectedComponents(self.graph) assert cc.count() == 2 self.assert_connected(cc, [0, 1, 2, 3, 4, 5]) self.assert_connected(cc, [6, 7, 8]) self.assert_not_connected(cc, 0, [6, 7, 8]) self.assert_not_connected(cc, 7, [0, 1, 2, 3, 4, 5]) def assert_connected(self, cc, connected_vertices_keys): for i in range(len(connected_vertices_keys) - 1): for j in range(i + 1, len(connected_vertices_keys)): v1 = self.graph.vertex(connected_vertices_keys[i]) v2 = self.graph.vertex(connected_vertices_keys[j]) assert cc.connected(v1, v2) assert cc.component_id(v1) == cc.component_id(v2) def assert_not_connected(self, cc, key, unconnected_vertices_keys): v = self.graph.vertex(key) for key in unconnected_vertices_keys: other_v = self.graph.vertex(key) assert not cc.connected(v, other_v) assert cc.component_id(v) != cc.component_id(other_v)
class TestGraph: def setup_method(self): self.graph = Graph() def test_add_vertex(self): self.graph.add_vertex(1) assert self.graph.vertex(1).key == 1 def test_add_vertex_update_existing(self): self.graph.add_vertex(1, 100) assert self.graph.vertex(1).value == 100 self.graph.add_vertex(1, 200) assert self.graph.vertex(1).value == 200 def test_add_edge_should_add_vertex_if_not_exist(self): assert self.graph.vertex(1) is None assert self.graph.vertex(2) is None self.graph.add_edge(1, 2) assert self.graph.vertex(1) is not None assert self.graph.vertex(2) is not None def test_get_adjacents(self): self.graph.add_vertex(1) self.graph.add_edge(1, 2) self.graph.add_edge(1, 3) self.assert_adjacents(1, [2, 3]) self.assert_adjacents(2, [1]) self.assert_adjacents(3, [1]) def assert_adjacents(self, key, expected_adj_keys): adjacents = self.graph.adj(key) adj_keys = [adj.key for adj in adjacents] assert has_same_items(adj_keys, expected_adj_keys)
class TestDepthFirstSearch: def setup_method(self): self.graph = Graph() def test_search_all_connected_vertices(self): self.graph.add_edge(0, 1) self.graph.add_edge(0, 2) self.graph.add_edge(0, 5) self.graph.add_edge(1, 2) self.graph.add_edge(2, 3) self.graph.add_edge(2, 4) self.graph.add_edge(3, 4) self.graph.add_edge(3, 5) self.graph.add_edge(6, 7) self.graph.add_edge(6, 8) self.graph.add_edge(7, 8) dfs = DepthFirstSearch(self.graph.vertex(0)) assert dfs.count() == 6 self.assert_marked(dfs, [0, 1, 2, 3, 4, 5]) dfs = DepthFirstSearch(self.graph.vertex(6)) assert dfs.count() == 3 self.assert_marked(dfs, [6, 7, 8]) def assert_marked(self, dfs, marked_keys): for key in marked_keys: assert dfs.marked(self.graph.vertex(key))