[C++]이진 검색 트리(높이1) - 백준1539

문제



풀이

문제 해석을 하자면,

  • 입력으로 P배열이 주어지면, 이 배열을 통해서 이진 검색 트리를 만들었을때 각 노드들 높이의 총 합을 구하는 문제이다.
    • 문제 자체는 매우 간단해 보이는데, 전혀 쉽지 않았다,,


풀이

  • 이 문제의 경우 구글링의 힘을 빌려서 해결하게 된 아쉬운 문제이다.
  • 초기에는 직접 BST를 구현해서 시뮬을 돌렸는데 편향이진트리 때문에 N^2이라 시간초과 발생하였다..
  • RBT는 NlogN이라 좋은데 BST의 높이와 달라서 정답이 틀릴테고..
    결국 구글링을 해보니 lower_bound 를 사용하는 방법으로 해결할 수 있다고 한다ㅜㅜ
    쉽다고 생각한건 큰 착각이였네 ,,
  • (참고) 문제를 풀기 위해선 STL에서 제공하는 set, map을 공부할 필요가 있음.
    • 해당 자료구조는 RBT로 이루어져 있어서 insert, delete 등등 logN 연산을 보장!!
    • 그리고 높이는 https://blog.joonas.io/161 를 참고!!
      자신보다 바로 작거나 큰 수의 높이 중 큰 높이에 +1 을 하면 높이를 구할 수 있다.
    • 자신보다 바로 작거나 큰 수를 lower_bound를 통해서 logN 속도로 구할 수 있기 때문에 높이를 구하는것도 빠르게 구할 수 있다.
      • 트리를 inorder(중위순회) 해보면 오름차순으로 정렬되어 있음을 알 수 있고,
      • 때문에 당연히 lower_bound를 통해서 자신보다 바로 작거나 큰 수를 구할 수 있다.
      • 참고로 lower_bound가 왜 logN밖에 안걸리나??
        트리가(set,map) 정렬되어서 저장되어있기 때문에 이진 탐색을 하면 logN밖에 걸리지 않는다!
  • 필자는 구조가 달라서 높이다르니까 RBT써도 못구할거라 생각했었다.
    • “높이가 자신보다 바로 작거나 큰 수의 높이 중 더 큰 높이에 +1” 을 통해서 구할 수 있다는걸 몰랐었고, 애초에 따로 배열에 높이를 기록해나가면 된다는것도 생각 못했었기 때문이다.



코드

#include<iostream>
#include<set>
using namespace std;

set<int> s; 
int heights[250002];

int main() {
	long long result = 0;
	int N;
	int inNum = 0;
	cin >> N;

	for (int i = 0; i < N; i++) {
		cin >> inNum;
		
		auto iter = s.lower_bound(inNum);
		long long left, right;
		if (iter != s.begin()) { // s.begin()은 root주소
			auto left_iter = iter;
			left = heights[*(--left_iter)]; // 해당 위치의 값을 인덱스로 heights배열 접근
		}
		else {
			left = 0; // iter이 root면 left높이는 0
		}

		if (iter != s.end()) { // s.end()는 마지막 원소 다음 자리 주소
			right = heights[*iter];
		}
		else {
			right = 0; // iter이 마지막 원소 다음이란건 이미 최대크기 left를 구한상태
		}

		heights[inNum] = max(left, right) + 1;
		s.insert(inNum); // RBT에 삽입

		result += heights[inNum];
	}
	cout << result;
	return 0;
}



느낀점

이런 유형의 BST관련 문제들은 반드시 set, map 같은 자료구조로 해결하도록 익숙해지자.

직접 구현하는 것은 지양하도록 하자.

댓글남기기