diff --git a/JooKangSan/[week3]Queue/Find_the_location_of_a_point.js b/JooKangSan/[week3]Queue/Find_the_location_of_a_point.js new file mode 100644 index 0000000..070e5e3 --- /dev/null +++ b/JooKangSan/[week3]Queue/Find_the_location_of_a_point.js @@ -0,0 +1,11 @@ +function solution(dot) { + let queue = [...dot] + + const x = queue.shift(); + const y = queue.shift(); + + if(x > 0 && y > 0) return 1; + if(x < 0 && y > 0) return 2; + if(x < 0 && y < 0) return 3; + return 4; +} \ No newline at end of file diff --git a/JooKangSan/[week3]Queue/Making_Burgers.js b/JooKangSan/[week3]Queue/Making_Burgers.js new file mode 100644 index 0000000..457549f --- /dev/null +++ b/JooKangSan/[week3]Queue/Making_Burgers.js @@ -0,0 +1,46 @@ +function solution(ingredient) { + let stack = []; + let count = 0; + let i = 0; + + while(i < ingredient.length) { + stack.push(ingredient[i]); + + if(stack.length >= 4) { + const len = stack.length; + if(stack[len-4] === 1 && + stack[len-3] === 2 && + stack[len-2] === 3 && + stack[len-1] === 1) { + stack.splice(-4); + count++; + } + } + i++; + } + + return count; + } + +// function solution(ingredient) { +// let queue = [...ingredient]; +// let stack = []; +// let count = 0; + +// while(queue.length > 0) { +// stack.push(queue.shift()); + +// if(stack.length >= 4) { +// const len = stack.length; +// if(stack[len-4] === 1 && +// stack[len-3] === 2 && +// stack[len-2] === 3 && +// stack[len-1] === 1) { +// stack.splice(-4); +// count++; +// } +// } +// } + +// return count; +// } \ No newline at end of file diff --git a/JooKangSan/[week3]Queue/Number_of_ordered_pairs.js b/JooKangSan/[week3]Queue/Number_of_ordered_pairs.js new file mode 100644 index 0000000..fc008d3 --- /dev/null +++ b/JooKangSan/[week3]Queue/Number_of_ordered_pairs.js @@ -0,0 +1,21 @@ +function solution(n) { + let queue = []; + let count = 0; + for(let i = 1; i <= Math.sqrt(n); i++) { + if(n % i === 0) { + queue.push(i); + } + } + while(queue.length > 0) { + const num = queue.shift(); + const pair = n / num; + + if(num === pair) { + count++; + } else { + count += 2; + } + } + + return count; +} \ No newline at end of file diff --git a/JooKangSan/[week3]Queue/Pack_of_Cards.js b/JooKangSan/[week3]Queue/Pack_of_Cards.js new file mode 100644 index 0000000..426ff50 --- /dev/null +++ b/JooKangSan/[week3]Queue/Pack_of_Cards.js @@ -0,0 +1,17 @@ +function solution(cards1, cards2, goal) { + let queue1 = [...cards1]; + let queue2 = [...cards2]; + + for(let word of goal) { + if(queue1.length > 0 && word === queue1[0]) { + queue1.shift(); + } + else if(queue2.length > 0 && word === queue2[0]) { + queue2.shift(); + } + else { + return "No"; + } + } + return "Yes"; +} \ No newline at end of file diff --git a/JooKangSan/[week3]Queue/Queue.md b/JooKangSan/[week3]Queue/Queue.md new file mode 100644 index 0000000..a3cb658 --- /dev/null +++ b/JooKangSan/[week3]Queue/Queue.md @@ -0,0 +1,125 @@ +# JavaScript Queue Algorithm + +## 1. 큐(Queue)란? + +선입선출 원칙을 따르는 선형 자료구조 => 먼저 들어온 데이터가 먼저 나감 + +### 기본 특성 + +- 데이터는 한쪽 끝(rear)에서만 삽입되고, 다른 한쪽 끝(front)에서만 삭제됨 +- 주로 대기열 관리, 작업 스케줄링 등에 사용 + +## 2. 자바스크립트에서 큐 구현 방법 + +### 배열을 사용한 기본 구현 + +```javascript +// 1. 기본적인 배열 메서드 사용 +let queue = []; + +// 삽입 (enqueue) +queue.push(element); + +// 삭제 (dequeue) +queue.shift(); + +// 맨 앞 요소 확인 (peek) +queue[0]; + +// 큐가 비었는지 확인 +queue.length === 0; +``` + +## 3. 큐의 주요 활용 사례 + +### 3.1 너비 우선 탐색(BFS) + +```javascript +function bfs(graph, start) { + // 방문한 노드 저장 + const visited = new Set(); + + // 시작 노드를 큐에 추가 + const queue = [start]; + + // 큐가 빌 때까지 반복 + while (queue.length > 0) { + // 현재 노드 추출 + const vertex = queue.shift(); + // 방문하지 않은 노드라면 + if (!visited.has(vertex)) { + // 방문 처리 + visited.add(vertex); + // 인접 노드들을 큐에 추가 + queue.push(...graph[vertex]); + } + } + + return visited; +} +``` + +### 3.2 작업 처리 대기열 + +```javascript +function processTaskQueue(tasks) { + // 작업 목록을 큐로 변환 + const queue = [...tasks]; + // 결과 저장 배열 + const results = []; + + // 큐가 빌 때까지 반복 + while (queue.length > 0) { + // 작업 추출 + const task = queue.shift(); + // 작업 처리 + const result = processTask(task); + // 결과 저장 + results.push(result); + } + + return results; +} +``` + +### 3.3 이벤트 처리 + +```javascript +const eventQueue = { + // 이벤트 큐 초기화 + queue: [], + + // 새 이벤트 추가 + addEvent: function (event) { + this.queue.push(event); + }, + + processEvents: function () { + // 큐가 빌 때까지 반복 + while (this.queue.length > 0) { + // 이벤트 추출 + const event = this.queue.shift(); + // 이벤트 처리 + handleEvent(event); + } + }, +}; + +eventQueue.addEvent("event1"); +eventQueue.processEvents(); +``` + +## 4. 성능 고려사항 + +### 4.1 시간 복잡도 + +- Enqueue (삽입): O(1) +- Dequeue (삭제): O(n) - shift() 사용 시 +- Peek (조회): O(1) + +### 4.2 주의사항 + +1. 배열의 shift() 연산은 O(n)의 시간 복잡도를 가짐 +2. 대량의 데이터를 처리할 때는 최적화된 구현 방식 고려 +3. 메모리 관리에 주의 (불필요한 참조 제거) +4. 동시성 처리 시 적절한 동기화 메커니즘 사용 diff --git a/JooKangSan/[week3]Queue/Success_Login.js b/JooKangSan/[week3]Queue/Success_Login.js new file mode 100644 index 0000000..0c80eef --- /dev/null +++ b/JooKangSan/[week3]Queue/Success_Login.js @@ -0,0 +1,19 @@ +function solution(id_pw, db) { + let queue = [...db]; + + const [id, pw] = id_pw; + let hasId = false; + + while(queue.length > 0) { + const [dbId, dbPw] = queue.shift(); + + if(dbId === id) { + hasId = true; + if(dbPw === pw) { + return "login"; + } + } + } + + return hasId ? "wrong pw" : "fail"; +} \ No newline at end of file diff --git a/JooKangSan/[week3]Queue/Unusual_arrangement.js b/JooKangSan/[week3]Queue/Unusual_arrangement.js new file mode 100644 index 0000000..73b26e5 --- /dev/null +++ b/JooKangSan/[week3]Queue/Unusual_arrangement.js @@ -0,0 +1,19 @@ +function solution(numlist, n) { + let queue = [...numlist]; + let result = []; + + queue.sort((a, b) => { + const A = Math.abs(n - a); + const B = Math.abs(n - b); + if(A === B) { + return b - a; + } + return A - B; + }); + + while(queue.length > 0) { + result.push(queue.shift()); + } + + return result; +} \ No newline at end of file diff --git a/JooKangSan/[week3]Queue/Walk_in_the_park.js b/JooKangSan/[week3]Queue/Walk_in_the_park.js new file mode 100644 index 0000000..00d710f --- /dev/null +++ b/JooKangSan/[week3]Queue/Walk_in_the_park.js @@ -0,0 +1,29 @@ +function solution(park, routes) { + let queue = [...routes]; + + let [x, y] = park.map((s, i) => [s.indexOf('S'), i]).find(v => v[0] > -1); + + let [h, w] = [park.length, park[0].length]; + + while(queue.length) { + let [d, n] = queue.shift().split(' '); + let [nx, ny] = [x, y]; + let go = true; + + for(let i = 0; i < n; i++) { + if(d === 'N') ny--; + if(d === 'S') ny++; + if(d === 'W') nx--; + if(d === 'E') nx++; + + if(ny < 0 || ny >= h || nx < 0 || nx >= w || park[ny][nx] === 'X') { + go = false; + break; + } + } + + if(go) [x, y] = [nx, ny]; + } + + return [y, x]; +} \ No newline at end of file diff --git a/JooKangSan/[week4]hash/Athlete_who_did_not_finish.js b/JooKangSan/[week4]hash/Athlete_who_did_not_finish.js new file mode 100644 index 0000000..58efee5 --- /dev/null +++ b/JooKangSan/[week4]hash/Athlete_who_did_not_finish.js @@ -0,0 +1,6 @@ +function solution(participant, completion) { + participant.sort(); + completion.sort(); + + return participant.find((name, i) => name !== completion[i]); +} \ No newline at end of file diff --git a/JooKangSan/[week4]hash/Determine_the_order_of_treatment.js b/JooKangSan/[week4]hash/Determine_the_order_of_treatment.js new file mode 100644 index 0000000..5544717 --- /dev/null +++ b/JooKangSan/[week4]hash/Determine_the_order_of_treatment.js @@ -0,0 +1,11 @@ +function solution(emergency) { + const orderMap = {}; + + const sorted = [...emergency].sort((a, b) => b - a); + + sorted.forEach((value, index) => { + orderMap[value] = index + 1; + }); + + return emergency.map(value => orderMap[value]); +} \ No newline at end of file diff --git a/JooKangSan/[week4]hash/Hash.md b/JooKangSan/[week4]hash/Hash.md new file mode 100644 index 0000000..197ba42 --- /dev/null +++ b/JooKangSan/[week4]hash/Hash.md @@ -0,0 +1,161 @@ +# JavaScript Hash(Map) Algorithm + +## 1. 해시(Hash)란? +키-값 쌍으로 데이터를 저장하는 자료구조로, 빠른 데이터 검색을 지원합니다. + +### 기본 특성 +- 고유한 키를 통해 값에 접근 +- 상수 시간 O(1)의 검색 복잡도 +- 충돌 처리 메커니즘 필요 + +## 2. 자바스크립트에서 해시 구현 방법 + +### 2.1 객체를 사용한 기본 구현 +```javascript +// 기본적인 객체 사용 +const hash = {}; + +// 데이터 추가 +hash['key'] = 'value'; + +// 데이터 접근 +console.log(hash['key']); // 'value' + +// 데이터 삭제 +delete hash['key']; + +// 키 존재 확인 +console.log('key' in hash); +``` + +### 2.2 Map 객체 사용 +```javascript +// Map 객체 생성 +const hashMap = new Map(); + +// 데이터 추가 +hashMap.set('key', 'value'); + +// 데이터 접근 +console.log(hashMap.get('key')); // 'value' + +// 데이터 삭제 +hashMap.delete('key'); + +// 키 존재 확인 +console.log(hashMap.has('key')); +``` + +## 3. 해시의 주요 활용 사례 + +### 3.1 빈도수 계산 +```javascript +function countFrequency(arr) { + const frequency = {}; + + for(const item of arr) { + frequency[item] = (frequency[item] || 0) + 1; + } + + return frequency; +} + +// 사용 예시 +const arr = ['a', 'b', 'a', 'c', 'b', 'a']; +console.log(countFrequency(arr)); // { a: 3, b: 2, c: 1 } +``` + +### 3.2 중복 제거 +```javascript +function removeDuplicates(arr) { + const hash = {}; + const result = []; + + for(const item of arr) { + if(!hash[item]) { + hash[item] = true; + result.push(item); + } + } + + return result; +} + +// 사용 예시 +console.log(removeDuplicates([1, 2, 2, 3, 3, 3])); // [1, 2, 3] +``` + +### 3.3 Two Sum 문제 +```javascript +function findTwoSum(nums, target) { + const hash = {}; + + for(let i = 0; i < nums.length; i++) { + const complement = target - nums[i]; + + if(complement in hash) { + return [hash[complement], i]; + } + + hash[nums[i]] = i; + } + + return null; +} + +// 사용 예시 +console.log(findTwoSum([2, 7, 11, 15], 9)); // [0, 1] +``` + +## 4. 성능 고려사항 + +### 4.1 시간 복잡도 +- 삽입: O(1) +- 삭제: O(1) +- 검색: O(1) +- 충돌이 많은 경우: O(n) + +### 4.2 공간 복잡도 +- O(n), 여기서 n은 저장된 키-값 쌍의 수 + +### 4.3 주의사항 +1. 해시 충돌 처리 + - 체이닝 + - 개방 주소법 + +2. 메모리 사용 + - 적절한 초기 크기 설정 + - 동적 크기 조정 + +3. 키 선택 + - 고른 분포의 해시값 + - 효율적인 해시 함수 + +## 5. Map vs Object 비교 + +### 5.1 Map의 장점 +- 키로 모든 타입 사용 가능 +- 순서 보장 +- 크기를 쉽게 알 수 있음 +- 순회가 더 편리함 + +### 5.2 Object의 장점 +- 리터럴 문법 지원 +- JSON과의 호환성 +- 프로토타입 체인 +- 더 적은 메모리 사용 + +### 5.3 사용 예시 +```javascript +// Map +const map = new Map(); +map.set(1, 'one'); +map.set({}, 'object'); +map.set(() => {}, 'function'); + +// Object +const obj = { + 1: 'one', + 'key': 'value' +}; +``` \ No newline at end of file diff --git a/JooKangSan/[week4]hash/Make_B_from_A.js b/JooKangSan/[week4]hash/Make_B_from_A.js new file mode 100644 index 0000000..bb3c984 --- /dev/null +++ b/JooKangSan/[week4]hash/Make_B_from_A.js @@ -0,0 +1,15 @@ +function solution(before, after) { + const hash = {}; + + for(let char of before) { + hash[char] = (hash[char] || 0) + 1; + } + + for(let char of after) { + if(!hash[char]) return 0; + hash[char]--; + } + + // 모든 값이 0이면 1 반환 + return Object.values(hash).every(count => count === 0) ? 1 : 0; +} \ No newline at end of file diff --git a/JooKangSan/[week4]hash/Memory_Score.js b/JooKangSan/[week4]hash/Memory_Score.js new file mode 100644 index 0000000..b1cd954 --- /dev/null +++ b/JooKangSan/[week4]hash/Memory_Score.js @@ -0,0 +1,9 @@ +function solution(name, yearning, photo) { + const scoreMap = {}; + + name.forEach((n, i) => scoreMap[n] = yearning[i]); + + return photo.map(p => + p.reduce((sum, person) => sum + (scoreMap[person] || 0), 0) + ); +} \ No newline at end of file diff --git a/JooKangSan/[week4]hash/Morse_Code.js b/JooKangSan/[week4]hash/Morse_Code.js new file mode 100644 index 0000000..6663242 --- /dev/null +++ b/JooKangSan/[week4]hash/Morse_Code.js @@ -0,0 +1,12 @@ +function solution(letter) { + // 모스부호 해시맵 생성 + const morse = { + '.-':'a','-...':'b','-.-.':'c','-..':'d','.':'e','..-.':'f', + '--.':'g','....':'h','..':'i','.---':'j','-.-':'k','.-..':'l', + '--':'m','-.':'n','---':'o','.--.':'p','--.-':'q','.-.':'r', + '...':'s','-':'t','..-':'u','...-':'v','.--':'w','-..-':'x', + '-.--':'y','--..':'z' + }; + + return letter.split(' ').map(match => morse[match]).join(''); +} \ No newline at end of file diff --git a/JooKangSan/[week4]hash/Ranking.js b/JooKangSan/[week4]hash/Ranking.js new file mode 100644 index 0000000..b509be0 --- /dev/null +++ b/JooKangSan/[week4]hash/Ranking.js @@ -0,0 +1,7 @@ + +function solution(score) { + const sum = score.map((el) => (el[0] + el[1])); + let sortedSum = sum.slice().sort((a, b) => b - a); + + return sum.map((el) => sortedSum.indexOf(el) + 1); + } \ No newline at end of file diff --git a/JooKangSan/[week4]hash/keypad.js b/JooKangSan/[week4]hash/keypad.js new file mode 100644 index 0000000..a548faf --- /dev/null +++ b/JooKangSan/[week4]hash/keypad.js @@ -0,0 +1,64 @@ +function solution(numbers, hand) { + // 키패드를 열 기준 2차원 배열로 정의 + const keypad = [ + [1, 4, 7, "*"], // 왼쪽 열 + [2, 5, 8, 0], // 가운데 열 + [3, 6, 9, "#"] // 오른쪽 열 + ] + + // 각 숫자의 좌표를 Map으로 저장 + const getPos = new Map() + // 열과 행 기준으로 좌표 저장 + for(let x = 0; x < keypad.length; x++) { + for(let y = 0; y < keypad[x].length; y++) { + getPos.set(keypad[x][y], [x, y]) + } + } + + let left = getPos.get("*") // 왼손 시작 위치 + let right = getPos.get("#") // 오른손 시작 위치 + + // 두 좌표 사이의 거리 계산 + const getDist = ([x1, y1], [x2, y2]) => + Math.abs(x1 - x2) + Math.abs(y1 - y2) + + return numbers.map(num => { + const target = getPos.get(num) + + // 첫 번째 열은 무조건 왼손 + if(target[0] === 0) { + left = target + return "L" + } + + // 세 번째 열은 무조건 오른손 + if(target[0] === 2) { + right = target + return "R" + } + + // 가운데 열인 경우 거리 계산 + const leftDist = getDist(left, target) + const rightDist = getDist(right, target) + + // 거리가 같으면 주손잡이 기준 + if(leftDist === rightDist) { + if(hand === "right") { + right = target + return "R" + } else { + left = target + return "L" + } + } + + // 거리가 다르면 가까운 손 사용 + if(leftDist < rightDist) { + left = target + return "L" + } else { + right = target + return "R" + } + }).join("") +} \ No newline at end of file diff --git a/JooKangSan/[week5]Tree/Binary_Tree_Inorder_Traversal.js b/JooKangSan/[week5]Tree/Binary_Tree_Inorder_Traversal.js new file mode 100644 index 0000000..eb27c1e --- /dev/null +++ b/JooKangSan/[week5]Tree/Binary_Tree_Inorder_Traversal.js @@ -0,0 +1,14 @@ +function inorderTraversal(root) { + const result = []; + + function inorder(node) { + if (!node) return; + + inorder(node.left); + result.push(node.val); + inorder(node.right); + } + + inorder(root); + return result; +} \ No newline at end of file diff --git a/JooKangSan/[week5]Tree/Binary_Tree_Level_Order_Traversal.js b/JooKangSan/[week5]Tree/Binary_Tree_Level_Order_Traversal.js new file mode 100644 index 0000000..cba9ce1 --- /dev/null +++ b/JooKangSan/[week5]Tree/Binary_Tree_Level_Order_Traversal.js @@ -0,0 +1,36 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @return {number[][]} + */ +function levelOrder(root){ + if (!root) return []; + + const result = []; + const queue = [root]; + + while (queue.length > 0) { + const levelSize = queue.length; + const levelNodes = []; + + for (let i = 0; i < levelSize; i++) { + const node = queue.shift(); + levelNodes.push(node.val); + + if (node.left) queue.push(node.left); + if (node.right) queue.push(node.right); + } + + result.push(levelNodes); + } + + return result; + }; + \ No newline at end of file diff --git a/JooKangSan/[week5]Tree/Invert_Binary_Tree.js b/JooKangSan/[week5]Tree/Invert_Binary_Tree.js new file mode 100644 index 0000000..2633012 --- /dev/null +++ b/JooKangSan/[week5]Tree/Invert_Binary_Tree.js @@ -0,0 +1,20 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @return {TreeNode} + */ +function invertTree(root) { + if (!root) return null; + + [root.left, root.right] = [invertTree(root.right), invertTree(root.left)]; + + return root; + }; + \ No newline at end of file diff --git a/JooKangSan/[week5]Tree/Maximum_Depth_of_Binary_Tree.js b/JooKangSan/[week5]Tree/Maximum_Depth_of_Binary_Tree.js new file mode 100644 index 0000000..664ad2a --- /dev/null +++ b/JooKangSan/[week5]Tree/Maximum_Depth_of_Binary_Tree.js @@ -0,0 +1,17 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +function maxDepth(root) { + if (!root) return 0; + + return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1; +} \ No newline at end of file diff --git a/JooKangSan/[week5]Tree/Same_Tree.js b/JooKangSan/[week5]Tree/Same_Tree.js new file mode 100644 index 0000000..f0b8561 --- /dev/null +++ b/JooKangSan/[week5]Tree/Same_Tree.js @@ -0,0 +1,19 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} p + * @param {TreeNode} q + * @return {boolean} + */ +function isSameTree(p, q){ + if (!p && !q) return true; + if (!p || !q || p.val !== q.val) return false; + + return isSameTree(p.left, q.left) && isSameTree(p.right, q.right); + }; \ No newline at end of file diff --git a/JooKangSan/[week5]Tree/Tree.md b/JooKangSan/[week5]Tree/Tree.md new file mode 100644 index 0000000..c784acc --- /dev/null +++ b/JooKangSan/[week5]Tree/Tree.md @@ -0,0 +1,213 @@ +## 1. 트리(Tree)란? +계층적 관계를 표현하는 비선형 자료구조로, 노드들과 노드들을 연결하는 간선들로 구성됩니다. + +### 1.1 기본 용어 +- 노드(Node): 트리의 기본 요소 +- 루트(Root): 트리의 최상위 노드 +- 간선(Edge): 노드를 연결하는 선 +- 부모 노드: 상위 노드 +- 자식 노드: 하위 노드 +- 리프 노드: 자식이 없는 노드 +- 깊이(Depth): 루트에서 특정 노드까지의 거리 +- 높이(Height): 트리의 최대 깊이 + +## 2. 이진 트리 구현 + +### 2.1 노드 클래스 +```javascript +class Node { + constructor(value) { + this.value = value; + this.left = null; + this.right = null; + } +} +``` + +### 2.2 이진 트리 클래스 +```javascript +class BinaryTree { + constructor() { + this.root = null; + } + + // 노드 삽입 + insert(value) { + const newNode = new Node(value); + + if (!this.root) { + this.root = newNode; + return this; + } + + let current = this.root; + while(true) { + if (value < current.value) { + if (!current.left) { + current.left = newNode; + return this; + } + current = current.left; + } else { + if (!current.right) { + current.right = newNode; + return this; + } + current = current.right; + } + } + } +} +``` + +## 3. 트리 순회 방법 + +### 3.1 전위 순회(Pre-order) +```javascript +preOrder(node = this.root, result = []) { + if (node) { + result.push(node.value); // 현재 노드 + this.preOrder(node.left, result); // 왼쪽 서브트리 + this.preOrder(node.right, result); // 오른쪽 서브트리 + } + return result; +} +``` + +### 3.2 중위 순회(In-order) +```javascript +inOrder(node = this.root, result = []) { + if (node) { + this.inOrder(node.left, result); // 왼쪽 서브트리 + result.push(node.value); // 현재 노드 + this.inOrder(node.right, result); // 오른쪽 서브트리 + } + return result; +} +``` + +### 3.3 후위 순회(Post-order) +```javascript +postOrder(node = this.root, result = []) { + if (node) { + this.postOrder(node.left, result); // 왼쪽 서브트리 + this.postOrder(node.right, result); // 오른쪽 서브트리 + result.push(node.value); // 현재 노드 + } + return result; +} +``` + +### 3.4 레벨 순회(Level-order) +```javascript +levelOrder() { + if (!this.root) return []; + + const result = []; + const queue = [this.root]; + + while (queue.length) { + const node = queue.shift(); + result.push(node.value); + + if (node.left) queue.push(node.left); + if (node.right) queue.push(node.right); + } + + return result; +} +``` + +## 4. 이진 검색 트리(BST) + +### 4.1 기본 구현 +```javascript +class BST { + constructor() { + this.root = null; + } + + // 노드 삽입 + insert(value) { + const newNode = new Node(value); + + if (!this.root) { + this.root = newNode; + return this; + } + + let current = this.root; + while (true) { + if (value === current.value) return undefined; + if (value < current.value) { + if (!current.left) { + current.left = newNode; + return this; + } + current = current.left; + } else { + if (!current.right) { + current.right = newNode; + return this; + } + current = current.right; + } + } + } + + // 값 찾기 + find(value) { + if (!this.root) return false; + + let current = this.root; + while (current) { + if (value === current.value) return true; + if (value < current.value) { + current = current.left; + } else { + current = current.right; + } + } + return false; + } +} +``` + +## 5. 성능 고려사항 + +### 5.1 시간 복잡도 +- 삽입: O(log n) - 균형 트리의 경우 +- 검색: O(log n) - 균형 트리의 경우 +- 삭제: O(log n) - 균형 트리의 경우 +- 최악의 경우: O(n) - 불균형 트리의 경우 + +### 5.2 공간 복잡도 +- O(n) - n은 노드의 수 + +## 6. 트리 관련 알고리즘 + +### 6.1 최소 공통 조상(LCA) 찾기 +```javascript +function findLCA(root, n1, n2) { + if (!root) return null; + + if (root.value === n1 || root.value === n2) { + return root; + } + + const left = findLCA(root.left, n1, n2); + const right = findLCA(root.right, n1, n2); + + if (left && right) return root; + + return left ? left : right; +} +``` + +### 6.2 트리의 깊이 찾기 +```javascript +function findDepth(root) { + if (!root) return 0; + return Math.max(findDepth(root.left), findDepth(root.right)) + 1; +} +``` \ No newline at end of file