Leetcode 문제 1319 해결

11981 단어 leetcode
이 문제를 풀다
h tps : // / ㅇ t 여기. 코 m / p 로 b ぇ ms / 누 m 베 r 오 f 오 페라 치온 s - 마케 - 네와 rk - 이런 c d /

결과: 풀리지 않았다

어떤 접근 방식을 취했는가?



모든 노드를 연결하려고 하면 네트워크에서 고립된 노드의 수가 대답이라고 생각했다.
0부터 연결되지 않는 노드가 하나 있으면 네트워크를 하나만 바꿔야 한다고 생각했다. 이것이라고 이하의 패턴이 안 된다는 것은 나중에 깨달았다.



이 패턴에서는 나의 해법으로는 2개 바꿔야 하지만, 이 패턴에서는 하나로 좋다.
에서 0부터 절단된 Tree의 수를 세면 좋았다고 깨달았지만 때 이미 늦었다.

그럼 어떻게 해야 했는가

해법



우선 connections의 수가 노드의 수를 N으로 하면 connections분단된 네트워크를 그래프로 정의하면 최저 필요한 선은 그래프를 G개로 정의하면 G - 1개의 선이 필요하다. 그래서 그래프의 개수를 세어 버리면 이 문제는 종료가 된다.
조금 구체적으로 생각해 보면, 다음과 같이 그래프의 수가 하나(즉 모두 연결되어 있는 상태라고) 0개의 선이 필요.



그래프의 수가 2개이면, 0123의 어느 것으로부터 45를 향해 하나의 선이 그려지면 그러므로 모든 노드가 연결되게 된다


역시 G-1을 대답으로 하기 때문에 괜찮을 것 같다.

그런데 나의 생각도 이것에 가까운 곳이었지만, 그래프의 개수를 세는 곳의 실장에 곤란해 버렸다. (물론 시간 끊김도 있었지만)

여기에는 두 가지 구현 방법이 있습니다.

DFS



어떤 데이터 구조로 DFS를 하는가 하면 배열과 Set를 사용한다.
우선 노드 개수분의 배열을 준비하고 그 하나하나에 Set를 준비한다.
이미지로서는 이런 느낌



각 항목마다 set의 내용을 탐색해 가고, 이미 탐색 끝난 항목이 있었을 경우는 카운트는 0으로서 새롭게 나온 숫자만이 나온 항목은 1을 카운트 시키면, 모든 그래프 합계 할 수 있습니다.



빨강은 처음 도달했다는 것 회색은 이미 도달이 끝난 것을 나타내고 있다. 회색의 노드가 있으면 확실히 어딘가의 그래프에 속하고 있다는 것이므로 그 이후의 탐색을 할 필요가 없어진다.
각 항목에 대해 DFS를 실시하기 때문에 최초의 0의 노드를 탐색하면 1까지 연결된다, 나머지는 각 항목에 대해 조사해 가면 벌써 접속되고 있는 노드는 반드시 도착이 끝나므로 그래프 카운트는 되지 않게 된다.

이렇게 함으로써 해결할 수 있다.

샘플 코드
var makeConnected = function(n, connections) {
    if(connections.length < n - 1) {
        return -1
    }

    const group = Array.from({length: n}).map(() => new Set())
    for(const [i, j] of connections){
        group[i].add(j)
        group[j].add(i)
    }

    const seen = Array.from({length: n}).fill(0)

    function dfs(i) {
        if(seen[i]) {
            return 0
        }

        seen[i] = 1
        for(const j of group[i]) {
            dfs(j)
        }

        return 1
    }
    const graphCount = Array.from({length: n}).reduce((a,b,i) => a + dfs(i), 0)

    return graphCount - 1
}

소집합 연결 목록



이름 그대로이지만 그래프별로 연결리스트를 만드는 방법이다.
연결 리스트의 제일 root만을 각 리스트에 보존해 간다. 그런데 주어진 connections를 [[0,1],[0,2],[1,3],[0,3],[4,5]]로 하면 본래의 변환은 위이지만 변환을 정리하는 것 에 의해 아래와 같이 변환할 수 있다.



이것은 connections의 순서에 따라서도 변화하지만, 변경을 정리하는 것으로 변화가 없어지는 곳이 반드시 태어난다. 그것이 그래프의 루트가 된다. 따라서, 소집합 연결 리스트로 처리해 가고, 각 배열의 항목과 첨자를 비교하면 그래프가 몇개 포함되어 있는지를 카운트할 수 있다.

Example
var makeConnected = function(n, connections) {
    if(connections.length < n - 1) {
        return -1
    }

    const parent = Array.from({length: n}).map((a, i) => i)
    let countComponents = 0;

    for(const [i, j] of connections) {
        const p1 = findParent(parent, i);
        const p2 = findParent(parent, j);
        if(p1 != p2) {
            parent[p1] = p2;
        }
    }
    console.log(parent)
    for(let i = 0; i < n; i++){
        if(parent[i] == i) {
            countComponents++;
        }
    }   

    return countComponents - 1 
}

function findParent(par, i) {
    while(i != par[i]) {
        i = par[i]
    }
    return i
}

DFS 쪽은 상당히 직관적이었기 때문에 할 수 있어도 좋은 생각이 들었다.
해법 2는 필수 복습이다.

좋은 웹페이지 즐겨찾기