문제 설명: 카카오 프렌즈를 두 팀으로 나누고, 각 팀이 같은 곳을 다른 순서로 방문하도록 해서 먼저 순회를 마친 팀이 승리하는 것. 라이언은 방문할 곳의 2차원 좌표 값을 구하고 각 장소를 이진트리의 노드가 되도록 구성한 후, 순회 방법을 힌트로 주어 각 팀이 스스로 경로를 찾도록 할 계획. 라이언은 아래와 같은 특별한 규칙으로 트리 노드들을 구성한다.
트리를 구성하는 모든 노드의 x, y 좌표 값은 정수이다.
모든 노드는 서로 다른 x값을 가진다.
같은 레벨(level)에 있는 노드는 같은 y 좌표를 가진다.
자식 노드의 y 값은 항상 부모 노드보다 작다.
임의의 노드 V의 왼쪽 서브 트리(left subtree)에 있는 모든 노드의 x값은 V의 x값보다 작다.
임의의 노드 V의 오른쪽 서브 트리(right subtree)에 있는 모든 노드의 x값은 V의 x값보다 크다.
이진트리를 구성하는 노드들의 좌표가 담긴 배열 nodeinfo가 매개변수로 주어질 때, 노드들로 구성된 이진트리를 전위 순회, 후위 순회한 결과를 2차원 배열에 순서대로 담아 반환하는 함수를 작성
입력
nodeinfo의 길이는 1 이상 10,000 이하
nodeinfo[i] 는 i + 1번 노드의 좌표이며, [x축 좌표, y축 좌표] 순으로 들어있다.
모든 노드의 좌표 값은 0 이상 100,000 이하인 정수
트리의 깊이가 1,000 이하인 경우만 입력으로 주어진다.
출력: 전위 순회, 후위 순회 결과를 저장한 배열
풀이
이진 트리는 비단말 노드가 자식 노드를 최대 2개만 가질 수 있기 때문에 y좌표 내림차순, x좌표 오름차순으로 정렬한 후 값이 큰 y부터 차례대로 삽입하면 x값을 비교하면서 위의 조건들이 자연스레 만족되면서 위 그림과 같이 이진트리가 만들어짐
즉, 잘못된 순서로 입력되어지는 경우가 없기 때문에 다음 노드부터 x값 기준으로 부모보다 작으면 왼쪽 자식으로 크면 오른쪽 자식으로 보낸다. 둘 다 자식이 없으면 그 때는 자식을 생성한다.
y값이 같은게 중간 레벨에 1개 있거나 3개 이상 있는 경우는 없으므로 제대로 동작
맨 처음에 좌표마다 노드 번호를 저장 map<pii, int>
주의할 점: 전위 순회, 후위 순회는 일반적으로 알고 있는 순회가 아닌 그림의 순서를 참고해야 함.
정답 코드
#include <string>
#include <vector>
#include <algorithm>
#include <map>
#define X first
#define Y second
using namespace std;
typedef pair<int,int> pii;
map<pii, int> m;
struct Node {
pii c;
Node* l;
Node* r;
Node(pii c): c(c), l(nullptr), r(nullptr) {}
void insert(pii p) {
if (c.X > p.X) {
if (l) l->insert(p);
else l = new Node(p);
} else {
if (r) r->insert(p);
else r = new Node(p);
}
}
void preorder(vector<int>& v) {
v.push_back(m[c]);
if (l) l->preorder(v);
if (r) r->preorder(v);
}
void postorder(vector<int>& v) {
if (l) l->postorder(v);
if (r) r->postorder(v);
v.push_back(m[c]);
}
};
vector<vector<int>> solution(vector<vector<int>> nodeinfo) {
for (int i = 0; i < nodeinfo.size(); i++)
m[{nodeinfo[i][0], nodeinfo[i][1]}] = i+1;
sort(nodeinfo.begin(), nodeinfo.end(), [&](auto& a, auto& b) mutable {
if (a[1] == b[1]) return a[0] < b[0];
return a[1] > b[1];
});
// 이진 트리 생성
Node* root = new Node({nodeinfo[0][0], nodeinfo[0][1]});
for (int i = 1; i < nodeinfo.size(); i++)
root->insert({nodeinfo[i][0], nodeinfo[i][1]});
vector<int> v1, v2;
root->preorder(v1); // 전위 순회
root->postorder(v2); // 후위 순회
return {v1, v2};
}