LeetCode 133. 克隆圖 | Python
阿新 • • 發佈:2020-08-12
133. 克隆圖
題目來源:力扣(LeetCode)
https://leetcode-cn.com/problems/clone-graph
題目
給你無向 連通 圖中一個節點的引用,請你返回該圖的 深拷貝(克隆)。
圖中的每個節點都包含它的值 val(int)
和其鄰居的列表(list[Node]
)。
class Node {
public int val;
public List<Node> neighbo rs;
}
測試用例格式:
簡單起見,每個節點的值都和它的索引相同。例如,第一個節點值為 1(val = 1
),第二個節點值為 2(val = 2
),以此類推。該圖在測試用例中使用鄰接列表表示。
鄰接列表 是用於表示有限圖的無序列表的集合。每個列表都描述了圖中節點的鄰居集。
給定節點將始終是圖中的第一個節點(值為 1)。你必須將 給定節點的拷貝 作為對克隆圖的引用返回。
示例 1:
輸入:adjList = [[2,4],[1,3],[2,4],[1,3]]
輸出:[[2,4],[1,3],[2,4],[1,3]]
解釋:
圖中有 4 個節點。
節點 1 的值是 1,它有兩個鄰居:節點 2 和 4 。
節點 2 的值是 2,它有兩個鄰居:節點 1 和 3 。
節點 3 的值是 3,它有兩個鄰居:節點 2 和 4 。
節點 4 的值是 4,它有兩個鄰居:節點 1 和 3 。
示例 2:
輸入:adjList = [[]]
輸出:[[]]
解釋:輸入包含一個空列表。該圖僅僅只有一個值為 1 的節點,它沒有任何鄰居。
示例 3:
輸入:adjList = []
輸出:[]
解釋:這個圖是空的,它不含任何節點。
示例 4:
輸入:adjList = [[2],[1]]
輸出:[[2],[1]]
提示:
- 節點數不超過 100 。
- 每個節點值 Node.val 都是唯一的,
1 <= Node.val <= 100
。 - 無向圖是一個簡單圖,這意味著圖中沒有重複的邊,也沒有自環。
- 由於圖是無向的,如果節點 p 是節點 q 的鄰居,那麼節點 q 也必須是節點 p 的鄰居。
- 圖是連通圖,你可以從給定節點訪問到所有節點。
解題思路
思路:DFS、BFS
在這道題中,題目要求的是圖的深拷貝。題目所述的圖的深拷貝,其實就是要構建與原圖結構,值均一樣的圖,但是 其中的節點不能再是原圖的引用。
題目開頭說了,給定的是一個節點的引用。但後面的提示也提及,圖是連通的,可以從給定的節點中去訪問所有節點。那麼我們在進行訪問搜尋的時候,完成圖的深拷貝。
深度優先搜尋(DFS)
這裡先說下需要注意的地方,因為題目中明確說了,圖是無向圖,圖中的邊是無向邊。例如示例 4:
這裡節點 1 和節點 2 存在無向邊,也就是說節點 1 可以到節點 2,而節點 2 也可以到 節點 1。所以我們遍歷搜尋的時候要注意標記,否則的話容易陷入死迴圈。
下面是具體演算法:
- 前面說在遍歷訪問的時候進行標記,這裡我們藉助雜湊表來已經被訪問和克隆的節點。其中鍵表示的是原圖的節點,而值表示的是克隆圖中對應的節點;
- 從給定的節點開始向下搜尋,如果節點存在於雜湊表中,那麼直接返回雜湊表中的對應的節點;
- 如果節點並沒有被標記,那麼建立克隆節點,儲存到雜湊表中;
- 遞迴呼叫每個節點的鄰接點,將結果放到克隆鄰接點列表中。
具體的程式碼見【程式碼實現 # 深度優先搜尋】
廣度優先搜尋(BFS)
使用廣度優先搜尋,這裡同樣需要注意無向邊的問題。在這裡,同樣使用雜湊表來儲存已被訪問原圖的節點以及對應克隆節點。下面是具體的演算法:
- 使用雜湊表來儲存已被訪問原圖的節點以及對應克隆節點;
- 克隆給定的節點,儲存到雜湊表中。同時藉助輔助佇列,先將給定的節點放到佇列。
- 出隊,訪問該節點的所有鄰接點。如果節點不在雜湊表中,那麼克隆當前節點的鄰接點存入雜湊表中。同時將此鄰接點入隊,並將此鄰接點放到克隆圖中對應節點的鄰接表中。
- 重複直至佇列為空,表明圖遍歷結束。
具體的程式碼見【程式碼實現 # 廣度優先搜尋】
程式碼實現
# 深度優先搜尋
"""
# Definition for a Node.
class Node:
def __init__(self, val = 0, neighbors = []):
self.val = val
self.neighbors = neighbors
"""
class Solution:
def cloneGraph(self, node: 'Node') -> 'Node':
marked = {}
def dfs(node):
if not node:
return node
# 如果存在於雜湊表中,直接返回雜湊表儲存的值
if node in marked:
return marked[node]
# 不存在雜湊表中,那麼克隆節點,將其放入雜湊表中
clone_node = Node(node.val, [])
marked[node] = clone_node
# 遍歷節點的鄰接點,相鄰接點放到鄰接列表中
for neighbor in node.neighbors:
clone_node.neighbors.append(dfs(neighbor))
return clone_node
return dfs(node)
# 廣度優先搜尋
"""
# Definition for a Node.
class Node:
def __init__(self, val = 0, neighbors = []):
self.val = val
self.neighbors = neighbors
"""
class Solution:
def cloneGraph(self, node: 'Node') -> 'Node':
from collections import deque
marked = {}
def bfs(node):
if not node:
return node
# 克隆節點,放到雜湊表中
clone_node = Node(node.val, [])
marked[node] = clone_node
# 先將給定的節點入隊
queue = deque()
queue.append(node)
# 出隊,開始遍歷
while queue:
cur_node = queue.popleft()
for neighbor in cur_node.neighbors:
# 如果鄰接點不在雜湊表中,克隆鄰接點存入雜湊表中,並將鄰接點入隊
if neighbor not in marked:
marked[neighbor] = Node(neighbor.val, [])
queue.append(neighbor)
# 更新當前節點的鄰接列表,注意是克隆節點
marked[cur_node].neighbors.append(marked[neighbor])
return clone_node
return bfs(node)
實現結果
歡迎關注
公眾號 【書所集錄】