방향이 없는 간선들의 목록이 주어질 때, 연결된 정점의 컴포넌트(그룹들)가 몇 개인지 반환하는 함수를 작성하세요.
주어진 간선은 무향입니다.
[1, 2] 는 정점 1에서 정점 2로도 갈 수 있으며, 정점 2에서 정점 1로도 갈 수 있습니다.
입력
출력
예시 1
const result = connectedVertices([
[0, 1],
[2, 3],
[4, 5],
]);
console.log(result); // 3
해당 정점들은 아래와 같은 모양을 하고 있습니다.
예시2
const result = connectedVertices([
[0, 1],
[2, 3],
[3, 4],
[3, 5],
]);
console.log(result); // 2
해당 정점들은 아래와 같은 모양을 하고 있습니다.
todo 1. 매개변수로 받은 연결된 정점을 2차원 배열을 가지고 → 전체 그래프로 만들기
todo 2. 만든 그래프를 전체 탐색하면서 연결된 정점 그룹이 전체에서 총 몇 개 있는지 반환하기
// 정점의 수를 구하기 위해 가장 큰 정점의 숫자를 구하는 함수
const getMaxVertex = (edges) =>
edges.reduce((acc, edge) => {
const max = Math.max(...edge);
if (max > acc) return max;
return acc;
}, 0);
// 정점들을 연결해 주어진 그래프를 만드는 함수
const makeGraph = (edges, graph) => {
for (let i = 0; i < edges.length; i++) {
const vertex1 = edges[i][0];
const vertex2 = edges[i][1];
graph[vertex1][vertex2] = 1;
graph[vertex2][vertex1] = 1;
}
};
const dfs = (graph, vertex, visited) => {
visited[vertex] = true;
for (let next = 0; next < graph[vertex].length; next++) {
if (graph[vertex][next] === 1 && !visited[next]) {
dfs(graph, next, visited);
}
}
};
// 문제 풀이 함수
function connectedVertices(edges) {
let count = 0; // 그래프 뭉탱이 개수
const verticesCount = getMaxVertex(edges) + 1; // 총 정점의 개수 (가장 큰 정점 + 1)
const visited = new Array(verticesCount).fill(false); // 방문 여부 확인
const graph = new Array(verticesCount)
.fill(0)
.map(() => new Array(verticesCount).fill(0));
makeGraph(edges, graph);
for (let vertex = 0; vertex < verticesCount; ++vertex) {
if (!visited[vertex]) {
dfs(graph, vertex, visited);
count++;
}
}
return count;
}
코드를 뜯어보자 !
Todo 1. 매개변수로 받은 연결된 정점을 2차원 배열을 가지고 → 전체 그래프로 만들기
먼저, 주어진 edges 를 가지고 그래프를 인접 행렬(2차원 행렬)로 만들어 주어야 한다.
2차원 인접 행렬은 이어지지 않은 곳은 0, 이어진 곳은 1로 이루어진 행렬이다.
// 문제 풀이 함수
function connectedVertices(edges) {
// 정답이 될 그래프 뭉탱이 개수
let count = 0;
const verticesCount = // 총 정점의 개수(가장 큰 정점의 숫자 + 1)
// 정점의 방문 여부 확인
const visited = new Array(verticesCount).fill(false);
// 0으로 채워진 2차원 배열
const graph = new Array(verticesCount)
.fill(0).map(() => new Array(verticesCount).fill(0));
makeGraph(edges, graph); // 이어진 정점들은 1로 채워주는 함수
// 정답 그래프 뭉탱이 개수 리턴
return count;
}
// verticesCount 정점의 개수가 4개(A, B, C D) 라고 가정한다면
const verticesCount = 4
const graph = new Array(verticesCount)
.fill(0).map(() => new Array(verticesCount).fill(0));
/* 이와 같은 빈 그래프가 만들어 진다.
A B C D
A [ [ 0, 0, 0, 0 ]
B [ 0, 0, 0, 0 ],
C [ 0, 0, 0, 0 ],
D [ 0, 0, 0, 0 ] ]
*/
그래프의 이어져 있는 곳은 1로 채워주는 함수를 정의하자
문제에서 주어진 2차원 배열 edges에 이어진 정점들이 표시되어 있다.
// 그래프의 이어져 있는 곳을 1로 채우는 함수
const makeGraph = (edges, graph) => {
for (let i = 0; i < edges.length; i++) {
const vertex1 = edges[i][0];
const vertex2 = edges[i][1];
graph[vertex1][vertex2] = 1;
graph[vertex2][vertex1] = 1;
}
};
/* 만약 아래와 같이 이어진 그래프가 있다면 */
const edges = [
[0, 1], // A - B
[1, 2], // B - C
[2, 3], // C - D
];
const graph = new Array(4).fill(0).map(() => new Array(4).fill(0));
let fillGraph = makeGraph(edges, graph);
console.log(graph);
/* A B C D
A [ [ 0, 1, 0, 0 ],
B [ 1, 0, 1, 0 ],
C [ 0, 1, 0, 1 ],
D [ 0, 0, 1, 0 ] ]
*/
todo1. 이 끝났다. 본격적으로 todo2로 넘어가자
Todo 2. 만든 그래프를 전체 탐색하면서 연결된 정점 그룹이 전체에서 총 몇 개 있는지 반환하기
그래의 각 정점을 돌면서 방문하지 않았으면 dfs()
탐색 함수로 그래프의 연결된 모든 정점을 탐색한다.
더 이상 연결된 곳이 없으면 dfs()
를 빠져나오고 count를 1개 늘린다.
dfs()
를 만들기 위해 필요한 것 : graph, vretex(현재 정점), 방문 여부 // 문제 풀이 함수
function connectedVertices(edges) {
// 정답이 될 그래프 뭉탱이 개수
let count = 0;
const verticesCount = // 총 정점의 개수(가장 큰 정점의 숫자 + 1)
// 정점의 방문 여부 확인
const visited = new Array(verticesCount).fill(false);
// 0으로 채워진 2차원 배열
const graph = new Array(verticesCount)
.fill(0).map(() => new Array(verticesCount).fill(0));
makeGraph(edges, graph); // 이어진 정점들은 1로 채워주는 함수
/* 그래의 각 정점을 돌면서 방문하지 않았으면 dfs로 탐색 */
for (let vertex = 0; vertex < verticesCount; ++vertex) {
if (!visited[vertex]) {
dfs(graph, vertex, visited);
count++;
}
}
// 정답 그래프 뭉탱이 개수 리턴
return count;
}
dfs 탐색 함수를 만들면, todo2도 끝이 난다.
1. 우선 방문한 정점을 true로 바꿔준다.
2. 해당 정점의 행을 돌면서, 연결된 곳(1
인 곳, 즉 0이 아니므로 true
)이면서 아직 방문하지 않은 정점이면 그 정점으로 가서 다시 탐색을 한다(재귀)
const dfs = (graph, vertex, visited) => {
// 방문한 정점을 표시해준다.
visited[vertex] = true;
for (let next = 0; next < graph[vertex].length; next++) {
if (!visited[vertex] && graph[vertex][next]) {
dfs(graph, next, visited);
}
}
};
마지막으로 미뤄뒀던, 총 정점의 개수를 구하는 함수를 만들어 보자
총 정점의 개수는 주어진 edges 배열에서 가장 큰 수 + (번호가 0부터 시작하므로) 1개 이다.
// 총 정점의 개수(가장 큰 정점의 숫자 + 1)
const verticesCount = getMaxVertex(edges) + 1;
edges에서 가장 큰 수를 구하는 함수는 다음과 같다.
edges는 2차원 배열이다.
따라서 배열의 요소인 inner배열(= 변수 edge)들을 돌면서,
inner배열(= edge)의 요소인 숫자 중 큰 수(=변수 max)를 저장하고,
(= 변수 acc에 담고,)
다음 inner배열(= edge)의 큰 수(= max)와 acc를 비교해서, acc를 다시 할당한다.
const getMaxVertex = (edges) => {
return edges.reduce((acc, edge) => {
// edge = 배열의 요소 안에 들어있는 배열
// max = edge에 담긴 정점 2개 중 큰 수
let max = Math.max(...edge);
// 현재의 max가 acc(이전까지의 max)보다 크면 max가 acc가 된다.
if (max > acc) return max;
return acc;
}, 0);
};
만약 edges 가 다음과 같다면, verticesCount
는 4가 된다.
const edges = [
[0, 1], // A - B
[1, 2], // B - C
[2, 3], // C - D
];