Given the root of a Binary Search Tree (BST), return the minimum absolute difference between the values of any two different nodes in the tree.
Example 1:
Input: root = [4,2,6,1,3] Output: 1
Example 2:
Input: root = [1,0,48,null,null,12,49] Output: 1
Constraints:
[2, 104].0 <= Node.val <= 105
문제 링크: https://leetcode.com/problems/minimum-absolute-difference-in-bst/
이 문제는 이진 검색 트리(BST)의 가장 중요한 속성 하나를 알고 있는지 묻고 있습니다.
핵심 속성: BST를 중위 순회(In-order Traversal)하면, 노드 값들이 오름차순으로 정렬된 순서로 방문된다.
예를 들어, 예제 1의 [4,2,6,1,3] 트리를 중위 순회하면 1 → 2 → 3 → 4 → 6 순서가 됩니다.
최소 차이는 결국 이 정렬된 숫자들 중에서 서로 인접한 두 숫자 간의 차이 중 가장 작은 값이 됩니다. (즉, 2-1=1, 3-2=1, 4-3=1, 6-4=2 중 최소값은 1입니다.)
따라서, 모든 노드 쌍을 비교하는 O(N2)의 비효율적인 방법 대신, 중위 순회를 통해 O(N)으로 문제를 해결할 수 있습니다.
알고리즘은 매우 간단합니다.
현재 노드 값 - 이전 노드 값을 계산하여 최소 차이(minDiff)를 갱신합니다.이전 노드 값을 '현재 노드 값'으로 업데이트합니다.재귀를 이용한 중위 순회로 이 로직을 깔끔하게 구현할 수 있습니다. 재귀 호출 전반에 걸쳐 `prev`와 `minDiff` 값을 유지하기 위해 클래스 멤버 변수를 사용합니다.
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
// 직전 노드의 값을 저장할 변수. Integer 래퍼 타입을 사용해 null로 초기화.
private Integer prev = null;
// 최소 차이를 저장할 변수. 최댓값으로 초기화.
private int minDiff = Integer.MAX_VALUE;
public int getMinimumDifference(TreeNode root) {
inorder(root);
return minDiff;
}
private void inorder(TreeNode node) {
if (node == null) {
return;
}
// 1. 왼쪽 서브트리 순회
inorder(node.left);
// 2. 현재 노드 처리
if (prev != null) {
// 이전 노드가 존재하면, 현재 노드와의 차이를 계산하여 최소값 갱신
minDiff = Math.min(minDiff, node.val - prev);
}
// 현재 노드의 값을 prev로 업데이트
prev = node.val;
// 3. 오른쪽 서브트리 순회
inorder(node.right);
}
}
inorder(node.left);, // process node, inorder(node.right); 구조는 BST 관련 문제를 푸는 정석적인 패턴입니다. 이 순서만 지키면 자연스럽게 오름차순으로 노드를 방문하게 됩니다.prev와 minDiff 값은 유지되어야 합니다. 이를 위해 멤버 변수로 선언하여 재귀의 모든 깊이에서 공유하도록 했습니다.prev != null): prev를 Integer 래퍼 타입으로 선언하고 null로 초기화하면, 맨 처음 방문하는 노드(가장 작은 값)에 대해서는 차이를 계산하지 않고 `prev` 값을 초기화만 하는 로직을 간결하게 처리할 수 있습니다.