Leetcode 133. Clone Graph
Node pointer로 이루어진 graph 하나를 clone하는 문제. 중복된 edge는 없고, 각 Node가 가지고 있는 val은 unique하다는 조건에서 시작한다.
사실상 그렇게 어려운 문제는 아니다. DFS나 BFS를 쓰고, 그 과정에서 몇 줄만 추가해 주면 되는 문제.
첫 접근
일단 BFS로 풀었다. naive하게 2번의 BFS를 했다.
- 첫 BFS에서는 unvisit인 모든 Node에 대해 clone을 생성한다. 생성한 Node clone들을 value를 key로 가지는 map에 저장한다. ... 1
- 두 번째 BFS에서는 edge를 연결한다. 첫 번째 BFS에서 모든 Node를 찾았기 때문에 두 번째 BFS에서는 모든 clone들의 edge만 연결해 주면 된다.
// Runtime 9 ms Beats 23.26%
// Memory 8.8 MB Beats 65.38%
class Solution {
public:
Node* copyroot;
Node* cloneGraph(Node* node) {
if(node == NULL) return NULL;
queue<Node*> q;
set<Node*> visited;
map<int, Node*> m; // mapper of clone node
// ...1
q.push(node);
visited.insert(node);
while(!q.empty()){
Node* origin = q.front(); q.pop();
visited.insert(origin);
if(m.find(origin->val) == m.end()){
m[origin->val] = new Node(origin->val);
}
for(Node* adj : origin->neighbors){
if(visited.find(adj) == visited.end()){
q.push(adj);
}
}
}
// ... 2
q.push(node);
visited.clear();
visited.insert(node);
while(!q.empty()){
Node* origin = q.front(); q.pop();
visited.insert(origin);
for(Node* adj : origin->neighbors){
if(visited.find(adj) == visited.end()){
m[origin->val]->neighbors.push_back(m[adj->val]);
m[adj->val]->neighbors.push_back(m[origin->val]);
q.push(adj);
}
}
}
return m[1];
}
};
두 번째 접근
BFS 1번으로 해결할 수 없을까? 가능할 거라 생각했다. BFS에서 unvisit한 Node를 방문할 때 새 Node를 생성하고 map에 넣는다. 그렇지 않다면 이미 map에 들어가 있는 상태일 것이다.
따라서 어떤 Node의 neighbor를 탐색할 때 edge를 바로 연결해 줄 수 있다.
// Runtime 7 ms Beats 61.34%
// Memory 8.8 MB Beats 53.37%
class Solution {
public:
Node* copyroot;
Node* cloneGraph(Node* node) {
if(node == NULL) return NULL;
queue<Node*> q;
set<Node*> visited;
map<int, Node*> m; // mapper of clone node
q.push(node);
visited.insert(node);
while(!q.empty()){
Node* origin = q.front(); q.pop();
visited.insert(origin);
if(m.find(origin->val) == m.end()){
m[origin->val] = new Node(origin->val);
}
for(Node* adj : origin->neighbors){
if(m.find(adj->val) == m.end()){
m[adj->val] = new Node(adj->val);
q.push(adj);
}
m[origin->val]->neighbors.push_back(m[adj->val]);
}
}
return m[1];
}
};
세 번째 접근
조금 더 최적화했다. BFS의 모든 단계에서 [현 Node가 unvisit이면 새로운 Node를 생성]하고, 또 [현 Node의 모든 neighbor를 탐색할 때 unvisit이면 새로운 Node를 생성]하는 로직이 겹치기 때문에 이를 수정했다. 또 사용하지 않는 visited set을 버렸다.
// Runtime 7 ms Beats 61.34%
// Memory 8.7 MB Beats 65.38%
class Solution {
public:
Node* copyroot;
Node* cloneGraph(Node* node) {
if(node == NULL) return NULL;
queue<Node*> q;
map<int, Node*> m; // mapper of clone node
if(m.find(node->val) == m.end()){
m[node->val] = new Node(node->val);
}
q.push(node);
while(!q.empty()){
Node* origin = q.front(); q.pop();
for(Node* adj : origin->neighbors){
if(m.find(adj->val) == m.end()){
m[adj->val] = new Node(adj->val);
q.push(adj);
}
m[origin->val]->neighbors.push_back(m[adj->val]);
}
}
return m[1];
}
};
시간복잡도
각 접근마다 BFS를 2번, 또는 1번 하므로 O(V+E).
공간복잡도
worst case q, visited, set에 각각 O(V)만큼 들어간다. 따라서 O(V)
'PS > PS Log' 카테고리의 다른 글
23.04.10. 풀었던 문제들 (0) | 2023.04.10 |
---|---|
23.04.09. 풀었던 문제들 (0) | 2023.04.09 |
23.04.07. 풀었던 문제들 (0) | 2023.04.07 |
23.04.06. 풀었던 문제들 (0) | 2023.04.06 |
23.04.05. 풀었던 문제들 (0) | 2023.04.05 |