[LeetCode | Javascript] Minimum Absolute Difference in BST

박기영·2023년 9월 6일

LeetCode

목록 보기
29/41

solution

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var getMinimumDifference = function(root) {
    // BST는 부모 노드의 왼쪽 자식 노드는 부모보다 작고, 오른쪽 자식 노드는 부모보다 크다.
    // 트리는 같은 값이 나오지않는다!

    // 연결된 노드간의 차이만 따지는게 아니라, 연결되지 않은 노드들의 관계도 따져야하기 때문에
    // 정렬된 배열의 형태로 바꾸면 쉽다.
    // 왜? BST는 왼쪽이 부모보다 작고, 오른쪽이 부모보다 크다는 특징이 있지만,
    // 이 문제에서는 결국 최소 차이를 구하고 싶기 때문에 이런 특징 잘 활용되기는 어려워보이기 때문이다.
    // 가령, 왼쪽에 있는 값이 오른쪽 서브트리의 왼쪽 부분에 있는 값보다 클 수도 있고,
    // 오른쪽 노드에서도 1씩 증가한다면 왼쪽 노드보다도 훨씬 작은 차이를 가지기 때문에
    // 최소값이 왼쪽에서 나올 것이라 착각하면 안된다. 최소값은 어디서든 나올 수 있고,
    // 문제에서 요구하는 것은 불특정 두 개의 노드의 값 차이 중 최소를 구하는 것이기 때문에,
    // 왼쪽 서브트리만 탐색한다고 해서 최소 차이를 얻을 수 있는 것이 아니다.
    // 따라서
    // 트리 구조를 정렬된 배열 형태로 만든 뒤, 인접 인덱스간 차이를 비교해서 최소를 구하면 된다.
    // 정렬이 되면 적어도, 인접 인덱스를 비교하는 것으로 현재 노드에서 얻을 수 있는 최소 차이를 확정할 수 있기 때문에
    // 좋은 방법이라고 생각된다.
    const arrOfTree = convertToArray(root);

    // Tree에서는 같은 값이 존재하지 않으므로 노드 값 차이의 최소값은 1이 된다.
    let minDiff = 0;

    // 노드 간 차이를 봐야하기 때문에 length - 1까지 순회한다.
    for(let i = 0; i < arrOfTree.length - 1; i++){
        const diff = Math.abs(arrOfTree[i] - arrOfTree[i+1]);

        if(!minDiff){
            minDiff = diff;
            continue;
        }

        minDiff = Math.min(minDiff, diff);
    }
    
    return minDiff;
};

// 현재 root 변수는 트리 구조를 담고 있으며,
// 루트 노드, 왼쪽 자식 노드, 오른쪽 자식 노드, 왼쪽 자식 노드의 왼쪽 자식 노드, 왼쪽 자식 노드의 오른쪽 자식 노드,..
// 이런 식으로 전개되어 있다.
// BST는 루트 기준 왼쪽 서브 트리는 루트 값보다 작은 값들만 있고, 루트 기준 오른쪽 서브 트리는 루트 값보다 큰 값들만 있다.
function convertToArray(root, result=[]){
    if(!root){
        return;
    }

    // 왼쪽 자식 노드
    convertToArray(root.left, result);

    // 현재 노드
    result.push(root.val);

    // 오른쪽 자식 노드
    convertToArray(root.right, result);

    return result;
}

이 문제는 BST의 특성을 직접적으로 사용한다기 보다는,
그 특성을 기반으로 새로운 접근을 하는 듯한 느낌이었다.

문제에서 요구한 것은 무작위의 두 노드 간 차이 값이 최소인 것을 반환하는 것이었는데,
BSTTree 구조이므로, 무작위로 두 노드를 설정해서 차이값을 연산하는 것은 무리가 있어보였다.
이렇게되면 모든 노드에서 경우의 수를 다 따져야할텐데, 이게 과연 풀이를 해낼 수 있는 것인지 의문이었다.

BST의 특징은 다음과 같다.
Root Node의 왼쪽 SubTree에 있는 Node의 값들은 Root Node의 값보다 작다.
Root Node의 오른쪽 SubTree에 있는 Node의 값들은 Root Node의 값보다 크다.

이를 활용하면 트리를 정렬된 배열로 변환하는 것이 가능하다.
재귀를 활용해서 왼쪽을 최우선으로 배열에 넣은 뒤, 본인을 넣고, 오른쪽을 넣어주면 되는 것이다.
이 생각이 반영된 것이 convertToArray()이다.

이렇게 정렬된 배열로 변환한 뒤에, 앞에서부터 순회하면서 두 인덱스간 차이값을 비교하고,
그 중에서 최솟값을 구하면 된다!

인접한 노드에서만 연산이 진행될 수 있다는 조건이 없기 때문에 가능한 풀이이다 :)

다른 분의 solution

var getMinimumDifference = function(root) {
    let prev = -Infinity, minDiff = Infinity;
    const recursive = (node) => {
        if(!node) return;
        recursive(node.left);
        minDiff = Math.min(minDiff, node.val - prev);
        prev = node.val;
        recursive(node.right);
    }
    recursive(root);
    return minDiff;
};

필자가 배열로 변환한 뒤 연산을 진행한 반면, 이 분은 트리 구조를 유지한 채로 연산을 진행하셨다.
prev라는 이전 노드 값, 즉, 연산을 진행할 당시의 노드 값을 따로 뽑아놓고 진행하는 방법인듯 하다.
recursive()를 재귀로 사용하면서 왼쪽과 오른쪽 서브 트리를 탐색을 하고 있고,
prev와 현재 노드의 값을 비교하여 최솟값을 설정한다.

그러고보니..굳이 배열로 변환할 필요가 없었던 것이다!
BST 특성 상 두 노드간 최소값을 구하고자 한다면, 왼쪽이든 오른쪽이든 같은 쪽끼리만 연산하면 되기 때문이다.
트리가 갈라지는 순간, 이미 왼쪽과 오른쪽은 차이가 커져서 서로를 비교 대상으로 잡을 수 없게 되니 말이다.
따라서, 불특정 노드라는 말은 하지만, 노드 간 차이의 최소를 구하려면 현재 노드의 부모와 자식 사이에만 살펴보면 되는 문제였다.

profile
나를 믿는 사람들을, 실망시키지 않도록

0개의 댓글