이진트리 균형 확인문제
이진트리 균형 확인문제 — #이진트리 #이진트리문제 #이진트리균형확인 #개발자의도구들 사용된 언어: 코틀린, 혹은 파이썬 순서: 로...
#LeetCode#Naver Blog
#이진트리 #이진트리문제 #이진트리균형확인 #개발자의도구들
- 사용된 언어: 코틀린, 혹은 파이썬
- 순서: 로직, 코드 구현, 코드 분석
트리의 균형 확인하기
LeetCode(esay 110. Balanced Binary Tree)
문제:
이진트리가 균형(height-balanced)인지 아닌지를 확인하라.
class TreeNode(var 'val': Int) {
var left: TreeNode? = null,
var right: TreeNode? = null
}
`val`은 두 노드사이에서 중복이 가능함
* BST가 아닌 Binary Tree이다.
1. height balanced를 알아보려면 좌/우 노드의 높이 차이가 1이하 여야 한다.
오답코드
class Solution {
fun getHeight(root: TreeNode?): Int {
if (root == null) {
return 1
}
var leftHeight = 1
var rightHeight = 1
var leftTemp = root
while (leftTemp != null) {
leftTemp = leftTemp.left ?: break
leftHeight++
}
var rightTemp = root
while (rightTemp != null) {
rightTemp = rightTemp.right ?: break
rightHeight++
}
return maxOf(leftHeight, rightHeight)
}
fun isBalanced(root: TreeNode?): Boolean {
var leftHeight = 0
var rightHeight = 0
root?.left?.let {
leftHeight += getHeight(it)
}
root?.right?.let {
rightHeight += getHeight(it)
}
return if (leftHeight > rightHeight) {
leftHeight - rightHeight <= 1
} else {
rightHeight - leftHeight <= 1
}
}
}
- 단순히 좌/우의 최대 height 값만 비교해서는 안된다
- 이 코드는 자식 노드가 balnced한지를 알 수 없다.
✏️ 논리 수정하기
1. 자식에서 좌,우 대칭 여부를 확인해야한다.
2. recursive를 사용하면 좋을 것 같다.
정답코드
class Solution {
fun getHeight(root: TreeNode?): Int {
if (root == null) {
return 0
}
val leftHeight = getHeight(root.left)
val rightHeight = getHeight(root.right)
return 1 + maxOf(leftHeight, rightHeight)
}
fun isBalanced(root: TreeNode?): Boolean {
if (root == null) return true
val leftHeight = getHeight(root.left)
val rightHeight = getHeight(root.right)
if (abs(leftHeight - rightHeight) > 1) {
return false
}
return isBalanced(root.left) && isBalanced(root.right)
}
}
✒️ 개선된 것
1. 잘못된 Height
getHeight에서 left는 왼쪽으로만 이동하고, right는 오른쪽으로만 이동했다.
아래 케이스 대응이 불가함
1
/ \
2 3
/ \
4 5
\
6
1 leftHeight는 1, rightHeight는 3인데
기존 코드로는 1, 2로 되어서 차이가 1이므로 오답
2. abs를 사용하여 코드 길이 줄이기 - 기본적인 kotlin 모듈이 내장되어 있다.
3. recursive를 사용하여 모든 노드에 대하여 balanced 확인하기
- 기존 코드는 하나의 코드에서만 balnced 여부를 확인했었다.
⌚ 시간 복잡도 분석
해당 문제의 입력은 0~5000개의 노드
O(N^2)의 시간 복잡도.
1. 모든 노드의 높이 구할 때 O(N)
2. 각 노드가 balanced한지 체크할 때 O(N)
🛰️ 공간 복잡도 분석
재귀 호출: getHeight, isBalanced는 둘 다 재귀호출을 수행한다.
가장 깊은 경우 트리의 높이 만큼 스택 프레임이 쌓인다. O(h)
h는 평균적으로 logN(균형 트리), 최악의 경우 N까지 가능하다. (N은 노드 갯수)
O(log N) ~ O(N)
시간 복잡도를 줄여보자
정답 코드의 단점은 시간복잡도가 매우 크다는 것이다. 시간을 줄이기 위해 높이를 계산함과 동시에 균형여부를 확인하는 코드를 아래와 같이 작성할 수 있다.
class Solution {
fun optCheck(root: TreeNode?): Int {
if (root == null) return 0
val left = optCheck(root.left)
if (left == -1) return -1
val right = optCheck(root.right)
if (right == -1) return -1
if (abs(left - right) > 1) return -1
return 1 + maxOf(left, right)
}
fun isBalanced(root: TreeNode?): Boolean {
return optCheck(root) != -1
}
}
높이를 구함과 동시에, left와 right의 균형을 확인하여 불균형인 경우 -1을 내보낸다.
⭐ tip!
1. Height를 구할때는 1 + maxOf(left, right)패턴 기억하기