트리의 정의

 

정점(=노드) : 각각의 원소

루트 : 가장 꼭대기에 있는 정점

리프 : 자식이 없는 정점

간선 : 정점끼리 연결하는 선

서브트리 : 어떤 한 정점에 대해 그 밑에 있는 정점과 간선만을 모은 트리

이진트리 : 각 노드의 자식이 2개 이하인 트리

 

이진 검색 트리

 

왼쪽 서브트리의 모든 값은 부모의 값보다 작고, 오른쪽 서브트리의 모든 값은 부모의 값보다 큰 이진 트리

이진 검색 트리를 이용하면 insert, erase, find, update 모두 O(logN)에 처리할 수 있다.

 

이진 검색 트리를 사용해야 하는 문제가 있다면 map/set을 사용하면 된다.

보통 unordered_map/set이 조금더 빠르지만 해시충돌이 빈번하게 일어난다면 얘기가 달라지므로 언제나 O(logN)을 보장해주는 map/set을 이용하는게 낫다.

하지만 O(logN)중에서도 느린편이다.

 

 

코딩 테스트에서 STL을 사용하지 못하는 경우 이진 검색 트리로 풀 수 있을것 같은 문제라 하더라도 해시나 이분 탐색과 같은 다른 방법을 이용하는 풀이를 고민해야 한다.

 

연습 문제

 

7662: 이중 우선순위 큐

더보기
#include <bits/stdc++.h>
using namespace std;

int main(void)
{
	int tc;
	cin >> tc;
	while (tc--)
	{
		multiset<int> h;
		int k;
		cin >> k;
		while (k--)
		{
			char a;
			int b;
			cin >> a >> b;
			if (a == 'I')
				h.insert(b);
			else
			{
				if (h.empty()) continue;
				if (b == 1)	h.erase(prev(h.end()));
				else h.erase(h.begin());
			}
		}
		if (!h.empty()) cout << *h.rbegin() << ' ' << *h.begin();
		else cout << "EMPTY";
		cout << '\n';
	}
}

 

삭제할 때 prev(h.end())가 아니라 h.rbegin()을 넣어봤더니 reverse_iterator는 erase 할 수 없었다.

iterator로 변환해주는 base()를 쓰게되면 해당 iterator 그대로 변환되는게 아니라 이전 iterator가 반환된다.

또한 iterator가 아닌 참조한 값을 지우게 되면 중복값이 싸그리 지워지기 때문에 이 문제에서는 적합하지 않다.

 

1202: 보석 도둑

더보기

아직 내가 쉽게 이해할만한 문제가 아니라 패스함

 

기본 문제

 

21939: 문제 추천 시스템 Version 1

더보기
#include <bits/stdc++.h>
using namespace std;

int n, m;
map<int, set<int>> h;

int main(void)
{
	cin >> n;
	while (n--)
	{
		int a, b;
		cin >> a >> b;
		h[b].insert(a);
	}

	cin >> m;
	while (m--)
	{
		string s;
		cin >> s;
		if (s == "recommend")
		{
			int a;
			cin >> a;
			if (a == 1)	cout << *(prev(h.end())->second.rbegin()) << '\n';
			else cout << *h.begin()->second.begin() << '\n';
		}
		else if (s == "add")
		{
			int p, l;
			cin >> p >> l;
			h[l].insert(p);
		}
		else
		{
			int a;
			cin >> a;
			for (auto& it : h)
			{
				if (it.second.find(a) != it.second.end())
				{
					it.second.erase(a);
					if (it.second.empty()) h.erase(it.first);
					break;
				}
			}
		}
	}
}

 

map에 set을 쳐박아놔서 find->remove를 수행할 때 이점을 다 날려버리고 선형탐색을 시도해서 시간이 오래걸린다.

정답 코드는 set과 배열 두개를 사용해서 따로 관리하는 방법을 썼음

 

23326: 홍익 투어리스트

더보기
#include <bits/stdc++.h>
using namespace std;

int n, q;
set<int> p;

int main(void)
{
	ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);

	cin >> n >> q;
	for (int i = 1; i <= n; ++i)
	{
		int a;
		cin >> a;
		if (a) p.insert(i);
	}

	int cur = 1;
	while (q--)
	{
		int a;
		cin >> a;
		if (a == 1)
		{
			cin >> a;
			if (p.find(a) != p.end()) p.erase(a);
			else p.insert(a);
		}
		else if (a == 2)
		{
			cin >> a;
			cur = (cur + a - 1) % n + 1;
		}
		else
		{
			if (p.empty()) cout << -1 << '\n';
			else
			{
				auto it = p.lower_bound(cur);
				if (*it >= cur) cout << *it - cur << '\n';
				else cout << n - cur + *p.begin() << '\n';
			}
		}
	}
}

 

입출력 버퍼 부분 쥐도새도 모르게 지워져서 계속 시간초과 뜨길래 뇌정지옴

해답코드랑 비교해보니 쿼리가 2일때 cur값 주는 부분만 조건식을 썼냐 안썼냐 차이였음

'알고리즘 > 바킹독의 실전 알고리즘' 카테고리의 다른 글

[0x18] 그래프  (0) 2022.08.07
[0x17] 우선순위 큐  (0) 2022.08.07
[0x15] 해시  (0) 2022.08.06
[0x14] 투 포인터  (0) 2022.08.05
[0x13] 이분탐색  (0) 2022.08.05

+ Recent posts