일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 코딩일기
- 구현
- 티스토리챌린지
- 개발 회고
- poiemaweb
- JavaScript
- State
- 자바스크립트
- 수학
- HTML5
- 회고
- 자바
- 세그먼트 트리
- REACT
- 오블완
- 해시를 사용한 집합과 맵
- 토이 프로젝트
- 브루트포스
- 자료 구조
- 엔트리포인트
- 시뮬레이션
- 모던 자바스크립트 튜토리얼
- 프론트엔드
- Next.js
- three.js
- 백준
- js
- react-three/fiber
- 기본 문법
- styled-components
- Today
- Total
코딩하는 고릴라
[Javascript] BOJ_2263. 트리의 순회 본문
🦍 문제
https://www.acmicpc.net/problem/2263

🐈 문제 풀이
1. 무엇을 구해야 할까?
이진트리의 중위 순회와 후위 순회 결과값이 주어졌을 때, 이를 바탕으로 전위 순회 결과를 구해야 한다.
2. 어떻게 구해야 할까?
중위 순회, 후위 순회 결과에서 규칙을 찾아내, 재귀적으로 탐색하게끔 하면 전위 순회를 구할 수 있다.
3. 특별히 고려해야 할 사항은?
주어지는 n 값(노드의 개수)이 최대 100,000이다. Node.js 환경에서는 콜스택의 최대 크기가 대략 10,000이므로, 재귀함수를 통해 풀이하면 Maximum call stack size exceeded 에러를 만날 수 있다. 따라서 스택을 활용해 재귀함수를 활용한 것과 같은 동작을 하게끔 해야 한다.
중위 순회, 후위 순회로부터 전위 순회 결과를 얻어내기 위한 접근법

위와 같은 트리가 존재할 때, 이 트리의 중위 순회와 후위 순회 결과는 위와 같다.
재귀적으로 전위 순회를 얻어내려면, 각 단계에서의 root와 해당 root로부터 파생되는 양쪽의 서브트리를 파악해야 한다.

첫 단계에서의 root 노드를 파란색으로 표시해 보면 어느 정도 규칙을 찾을 수 있다.
후위 순회 결과에서 가장 뒤쪽에 위치한 1이 바로 root임을 알 수 있고,
중위 순회에서는 root인 1을 기준으로 잡았을 때, 좌/우로 각각 서브트리가 위치함을 알 수 있다.

위쪽의 이미지에서 해당 단계에서 각각 유효한 중위 순회, 후위 순회의 범위도 표시해 봤다.
다음 단계로 넘어가며 양 쪽 서브트리를 탐색하는 모습도 그려보자면 다음과 같다.


각각 좌측 서브트리, 우측 서브트리에 대한 모습을 표현해 봤다.
위 이미지에서도 확인이 가능하듯, 후위 순회에서 유효한 범위 내 가장 뒤쪽에 있는 노드가 root를 가리킴을 알 수 있으며, 중위 순회에서는 해당 root를 기준으로 좌, 우로 서브트리가 형성돼있음을 알 수 있다.
또한, 해당 유효 범위를 설정해 나감에 있어 중위 순회가 가지는 범위와 후위 순회가 가지는 범위가 상이함을 알 수 있다.
- 중위 순회 결과
- 후위 순회 결과
- 중위 순회에서의 범위를 나타낼 양 끝의 두 인덱스
- 후위 순회에서의 범위를 나타낼 양 끝의 두 인덱스
결과적으로 위 네 가지 정보를 토대로 문제를 해결할 수 있다.
여기서 가장 애를 먹었던 부분은 범위를 좁혀나감에 있어 양 끝 인덱스를 어떻게 설정해줘야 할지였는데, 머리로 쉽사리 그려지지 않아 그림을 그려가며 풀이했었다.
🐕🦺 소스 코드
const input = require('fs').readFileSync('/dev/stdin').toString().trim().split('\n');
function solution() {
let idx = 0;
const N = Number(input[idx++]);
const inOrder = input[idx++].split(' ').map(Number);
const postOrder = input[idx++].split(' ').map(Number);
const answer = [];
const stack = [];
stack.push([0, N - 1, 0, N - 1]); // inL, inR, postL, postR
while (stack.length !== 0) {
let [inL, inR, postL, postR] = stack.pop();
if (inL > inR || postL > postR) {
continue;
}
const root = postOrder[postR];
answer.push(root);
let rootIndex;
for (let i = inL; i <= inR; i++) {
if (inOrder[i] === root) {
rootIndex = i;
break;
}
}
stack.push([rootIndex + 1, inR, postL + rootIndex - inL, postR - 1]);
stack.push([inL, rootIndex - 1, postL, postL + rootIndex - 1 - inL]);
// 재귀함수가 아닌 스택을 활용하고 있으므로 stack에 push해주는 순서도 고려해야한다.
// 스택에 먼저 들어간 값이 나중에 나옴을 인지하고, 전위 순회를 위해 우측 서브트리에 대한
// 값을 우선적으로 push해줬다.
// 이는 재귀 함수를 활용할때와는 반대의 순서를 가진다.
}
return answer.join(' ');
}
console.log(solution());

🐖 Think
- 기존에 유사한 문제를 slice를 활용해 잘라진 배열을 만들어나가 쉽게 풀이했던 경험이 있었는데, 계속해서 생성되는 배열에 대한 공간복잡도를 고려하지 못했었다. 위와 같은 방법을 통하면 메모리적으로 최적화가 가능함을 느낄 수 있었다.
'APS' 카테고리의 다른 글
[Javascript] Algospot_JUMPGAME. 외발뛰기 (2) | 2024.10.04 |
---|---|
[Java] BOJ_1541. 잃어버린 괄호 (0) | 2024.02.11 |
[Javascript] BOJ_20055. 컨베이어 벨트 위의 로봇 (1) | 2023.12.30 |
[Javascript] BOJ_14500. 테트로미노 (0) | 2023.12.18 |
[Javascript] BOJ_17144. 미세먼지 안녕! (0) | 2023.12.18 |