├── 1장 ├── 1-1.js ├── 1-10.js ├── 1-11.js ├── 1-12.js ├── 1-13.js ├── 1-14.js ├── 1-15.js ├── 1-16.js ├── 1-17.js ├── 1-2.js ├── 1-3.js ├── 1-4.js ├── 1-5.js ├── 1-6.js ├── 1-7.js ├── 1-8.js └── 1-9.js ├── 2장 ├── 2-1.js ├── 2-10.js ├── 2-11.js ├── 2-12.js ├── 2-13.js ├── 2-14.js ├── 2-15.js ├── 2-16.js ├── 2-17.js ├── 2-18.js ├── 2-19.js ├── 2-2.c ├── 2-20.js ├── 2-21.js ├── 2-22.js ├── 2-23.js ├── 2-24.js ├── 2-25.js ├── 2-26.js ├── 2-27.js ├── 2-28.js ├── 2-29.js ├── 2-3.js ├── 2-30.js ├── 2-31.js ├── 2-32.js ├── 2-33.js ├── 2-34.js ├── 2-35.js ├── 2-36.js ├── 2-37.js ├── 2-38.js ├── 2-39.js ├── 2-4.js ├── 2-40.js ├── 2-41.js ├── 2-42.js ├── 2-43.js ├── 2-44.js ├── 2-45.js ├── 2-46.js ├── 2-47.js ├── 2-48.js ├── 2-49.js ├── 2-5.js ├── 2-50.js ├── 2-51.js ├── 2-52.js ├── 2-6.js ├── 2-7.js ├── 2-8.js └── 2-9.js ├── 3장 ├── 3-1.js ├── 3-10.js ├── 3-11.js ├── 3-12.js ├── 3-13.js ├── 3-14.js ├── 3-15.js ├── 3-16.js ├── 3-17.js ├── 3-18.js ├── 3-19.js ├── 3-2.js ├── 3-20.js ├── 3-21.js ├── 3-22.js ├── 3-23.js ├── 3-24.js ├── 3-25.js ├── 3-26.js ├── 3-27.js ├── 3-28.js ├── 3-29.js ├── 3-3.js ├── 3-30.js ├── 3-31.js ├── 3-4.js ├── 3-5.js ├── 3-6.js ├── 3-7.js ├── 3-8.js └── 3-9.js ├── 4장 ├── 4-1.js ├── 4-2.js ├── 4-3.js ├── 4-4.js ├── 4-5.js └── 4-6.js ├── 5장 ├── 5-1.js ├── 5-2.js ├── 5-3.js ├── 5-4.js ├── 5-5.js ├── 5-6.js ├── 5-7.js └── 5-8.js ├── 6장 ├── 6-1.js ├── 6-2.js ├── 6-3.js ├── 6-4.js ├── 6-5.js └── 6-6.js ├── 7장 ├── 7-1.js ├── 7-2.js ├── 7-3.js └── 7-4.js └── README.md /1장/1-1.js: -------------------------------------------------------------------------------- 1 | console.log("Hello world!"); -------------------------------------------------------------------------------- /1장/1-10.js: -------------------------------------------------------------------------------- 1 | function factorial(n) { 2 | return n > 0 ? n * factorial(n - 1) : 1; 3 | } 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /1장/1-11.js: -------------------------------------------------------------------------------- 1 | function factorial(n) { 2 | let fac = 1; 3 | for (let i = 1; i <= n; i++) { 4 | fac = fac * i; 5 | } 6 | return fac; 7 | } 8 | -------------------------------------------------------------------------------- /1장/1-12.js: -------------------------------------------------------------------------------- 1 | function addLoopCount(n) { 2 | let count = 0; 3 | for (let i = 0; i < n; i++) { 4 | count += 1; 5 | } 6 | return count; 7 | } 8 | -------------------------------------------------------------------------------- /1장/1-13.js: -------------------------------------------------------------------------------- 1 | function addLoopCount(n) { 2 | let count = 0; 3 | for (let i = 0; i < 10 * n; i++) { 4 | count += 1; 5 | } 6 | return count; 7 | } 8 | -------------------------------------------------------------------------------- /1장/1-14.js: -------------------------------------------------------------------------------- 1 | function addLoopCount(n) { 2 | let count = 0; 3 | for (let i = 0; i < n; i++) { 4 | count += 1; 5 | } 6 | count += count; 7 | return count; 8 | } 9 | -------------------------------------------------------------------------------- /1장/1-15.js: -------------------------------------------------------------------------------- 1 | function addLoopCount(n) { 2 | let count = 0; 3 | for (let i = 0; i < n; i++) { 4 | count += 1; 5 | } 6 | for (let i = 0; i < 10 * n; i++) { 7 | count += 1; 8 | } 9 | return count; 10 | } 11 | -------------------------------------------------------------------------------- /1장/1-16.js: -------------------------------------------------------------------------------- 1 | function addLoopCount(n) { 2 | let count = 0; 3 | for (let i = 0; i < n * n; i++) { 4 | count += 1; 5 | } 6 | return count; 7 | } 8 | -------------------------------------------------------------------------------- /1장/1-17.js: -------------------------------------------------------------------------------- 1 | function addLoopCount(n) { 2 | let count = 0; 3 | for (let i = 0; i < n; i++) { 4 | // 1번 반복문 5 | for (let i = 0; i < 10 * n; i++) { 6 | // 2번 반복문 7 | count += 1; 8 | } 9 | } 10 | return count; 11 | } 12 | -------------------------------------------------------------------------------- /1장/1-2.js: -------------------------------------------------------------------------------- 1 | console.log("Hello 민준"); 2 | console.log("Hello 서윤"); 3 | console.log("Hello 지우"); 4 | console.log("Hello 지호"); 5 | console.log("Hello 준우"); 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /1장/1-3.js: -------------------------------------------------------------------------------- 1 | const friends = ["민준", "서윤", "지우", "지호", "준우"]; 2 | for (let i = 0; i < friends.length; i++) { 3 | console.log("Hello " + friends[i]); 4 | } 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /1장/1-4.js: -------------------------------------------------------------------------------- 1 | const friends = ["민준", "서윤", "지우", "지호", "준우"]; 2 | friends.forEach((name) => console.log("Hello " + name)); -------------------------------------------------------------------------------- /1장/1-5.js: -------------------------------------------------------------------------------- 1 | let friends = ["민준", "서윤", "지우", "지호", "준우"]; 2 | 3 | function addFamilyName(array) { 4 | let newFriends = []; 5 | for (let i = 0; i < array.length; i++) { 6 | newFriends.push("김" + array[i]); 7 | } 8 | return newFriends; 9 | } 10 | friends = addFamilyName(friends); 11 | -------------------------------------------------------------------------------- /1장/1-6.js: -------------------------------------------------------------------------------- 1 | let friends = ["민준", "서윤", "지우", "지호", "준우"]; 2 | friends = friends.map((name) => "김" + name); 3 | -------------------------------------------------------------------------------- /1장/1-7.js: -------------------------------------------------------------------------------- 1 | const a = 1; 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /1장/1-8.js: -------------------------------------------------------------------------------- 1 | function loop(n) { 2 | for (let i = 0; i < n; i++) { 3 | console.log("Hello"); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /1장/1-9.js: -------------------------------------------------------------------------------- 1 | function loop(n) { 2 | for (let i = 0; i < n; i++) { 3 | for (let j = 0; j < n; j++) { 4 | console.log("Hello"); 5 | } 6 | } 7 | } 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /2장/2-1.js: -------------------------------------------------------------------------------- 1 | let a; // 메모리 할당, a = undefined 2 | a = 1; // 데이터 타입이 변경되며 메모리 할당, a = 1 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /2장/2-10.js: -------------------------------------------------------------------------------- 1 | function selectionSort(array) { 2 | let indexMin, temp; 3 | for (let i = 0; i < array.length - 1; i++) { 4 | indexMin = i; // 변경의 대상이 되는 기준 원소의 인덱스 5 | for (let j = i + 1; j < array.length; j++) { 6 | if (array[j] < array[indexMin]) { // O(1) 7 | indexMin = j; 8 | } 9 | } 10 | temp = array[indexMin]; 11 | array[indexMin] = array[i]; 12 | array[i] = temp; 13 | } 14 | return array; 15 | } -------------------------------------------------------------------------------- /2장/2-11.js: -------------------------------------------------------------------------------- 1 | let countries = [ 2 | { country: "Korea", gold: 5, silver: 4, bronze: 2, games: 10 }, 3 | { country: "USA", gold: 5, silver: 3, bronze: 2, games: 9 }, 4 | { country: "Japan", gold: 5, silver: 2, bronze: 4, games: 11 }, 5 | { country: "China", gold: 5, silver: 2, bronze: 2, games: 12 }, 6 | { country: "Germany", gold: 4, silver: 3, bronze: 3, games: 9 }, 7 | ]; 8 | -------------------------------------------------------------------------------- /2장/2-12.js: -------------------------------------------------------------------------------- 1 | function rankCountries(countries) { 2 | let len = countries.length; 3 | for (let i = 0; i < len; i++) { 4 | let max = i; 5 | for (let j = i + 1; j < len; j++) { 6 | if (countries[max].gold < countries[j].gold) { 7 | max = j; 8 | } else if (countries[max].gold == countries[j].gold) { 9 | if (countries[max].silver < countries[j].silver) { 10 | max = j; 11 | } else if (countries[max].silver == countries[j].silver) { 12 | if (countries[max].bronze < countries[j].bronze) { 13 | max = j; 14 | } else if (countries[max].bronze == countries[j].bronze) { 15 | if (countries[max].games > countries[j].games) { 16 | max = j; 17 | } 18 | } 19 | } 20 | } 21 | } 22 | if (max != i) { 23 | let tmp = countries[i]; 24 | countries[i] = countries[max]; 25 | countries[max] = tmp; 26 | } 27 | } 28 | return countries; 29 | } 30 | 31 | let countries = [ 32 | { country: "Korea", gold: 5, silver: 4, bronze: 2, games: 10 }, 33 | { country: "USA", gold: 5, silver: 3, bronze: 2, games: 9 }, 34 | { country: "Japan", gold: 5, silver: 2, bronze: 4, games: 11 }, 35 | { country: "China", gold: 5, silver: 2, bronze: 2, games: 12 }, 36 | { country: "Germany", gold: 4, silver: 3, bronze: 3, games: 9 }, 37 | ]; 38 | 39 | console.log(rankCountries(countries)); 40 | -------------------------------------------------------------------------------- /2장/2-13.js: -------------------------------------------------------------------------------- 1 | function rankCountries(countries) { 2 | let len = countries.length; 3 | for (let i = 0; i < len; i++) { 4 | let max = i; 5 | for (let j = i + 1; j < len; j++) { 6 | if (countries[max].gold < countries[j].gold) { 7 | max = j; 8 | continue; 9 | } 10 | if ( 11 | countries[max].gold == countries[j].gold && 12 | countries[max].silver < countries[j].silver 13 | ) { 14 | max = j; 15 | continue; 16 | } 17 | if ( 18 | countries[max].silver == countries[j].silver && 19 | countries[max].bronze < countries[j].bronze 20 | ) { 21 | max = j; 22 | continue; 23 | } 24 | if ( 25 | countries[max].bronze == countries[j].bronze && 26 | countries[max].games > countries[j].games 27 | ) { 28 | max = j; 29 | } 30 | } 31 | } 32 | if (max != i) { 33 | let tmp = countries[i]; 34 | countries[i] = countries[max]; 35 | countries[max] = tmp; 36 | } 37 | return countries; 38 | } 39 | -------------------------------------------------------------------------------- /2장/2-14.js: -------------------------------------------------------------------------------- 1 | let potion = [5, 8, 6, 1, 9, 3]; 2 | -------------------------------------------------------------------------------- /2장/2-15.js: -------------------------------------------------------------------------------- 1 | let potion = [5, 8, 6, 1, 9, 3]; 2 | 3 | // 선택 정렬로 배열을 내림차순으로 정렬 4 | for (let i = 0; i < potion.length; i++) { 5 | let maxIdx = i; 6 | for (let j = i + 1; j < potion.length; j++) { 7 | if (potion[j] > potion[maxIdx]) { 8 | maxIdx = j; 9 | } 10 | } 11 | [potion[i], potion[maxIdx]] = [potion[maxIdx], potion[i]]; 12 | } 13 | 14 | console.log(potion); // [9, 8, 6, 5, 3, 1] 15 | -------------------------------------------------------------------------------- /2장/2-16.js: -------------------------------------------------------------------------------- 1 | let potion = [5, 8, 6, 1, 9, 3]; 2 | let sum = 0; 3 | let result = []; 4 | potion.some((effect, i) => { 5 | // (1) 6 | sum = 0; 7 | result = []; 8 | for (let j = i; j < potion.length; j++) { 9 | sum += potion[j]; 10 | result.push(potion[j]); 11 | if (sum < 15 && j === potion.length - 1) { 12 | break; 13 | } else if (sum === 15) { 14 | return true; // (2) 15 | } else if (sum > 15) { 16 | break; 17 | } 18 | } 19 | }); 20 | if (sum !== 15) { 21 | console.log("도망친다"); 22 | } else { 23 | console.log(result); // [8, 6, 1] 24 | } 25 | -------------------------------------------------------------------------------- /2장/2-17.js: -------------------------------------------------------------------------------- 1 | function insertSort(array) { 2 | for (let i = 1; i < array.length; i++) { 3 | let currentValue = array[i]; 4 | let j; 5 | for (j = i - 1; j >= 0 && array[j] > currentValue; j--) { 6 | array[j + 1] = array[j]; 7 | } 8 | array[j + 1] = currentValue; 9 | } 10 | return array; 11 | } 12 | -------------------------------------------------------------------------------- /2장/2-18.js: -------------------------------------------------------------------------------- 1 | let units = [ 2 | { name: "질럿", attack: 16 }, 3 | { name: "드라군", attack: 20 }, 4 | { name: "하이템플러", attack: 0 }, 5 | { name: "다크템플러", attack: 40 }, 6 | { name: "리버", attack: 100 }, 7 | { name: "아칸", attack: 30 }, 8 | ]; 9 | -------------------------------------------------------------------------------- /2장/2-19.js: -------------------------------------------------------------------------------- 1 | function insertionSort(units) { 2 | for (let i = 1; i < units.length; i++) { 3 | let key = units[i]; 4 | let j = i - 1; 5 | // 공격력을 기준으로 정렬 6 | while (j >= 0 && units[j].attack > key.attack) { 7 | units[j + 1] = units[j]; 8 | j = j - 1; 9 | } 10 | units[j + 1] = key; 11 | } 12 | return units; 13 | } 14 | let units = [ 15 | { name: "질럿", attack: 16 }, 16 | { name: "드라군", attack: 20 }, 17 | { name: "하이템플러", attack: 0 }, 18 | { name: "다크템플러", attack: 40 }, 19 | { name: "리버", attack: 100 }, 20 | { name: "아칸", attack: 30 }, 21 | ]; 22 | console.log(insertionSort(units)); 23 | -------------------------------------------------------------------------------- /2장/2-2.c: -------------------------------------------------------------------------------- 1 | short a = 1; // short 타입은 2바이트 사용, 정수, -32768 ~ 32767까지 값만 허용 2 | int b = 1; // int 타입은 4바이트 사용, 정수, -2147483648 ~ 2148493647까지 값만 허용 3 | char c = 1; // char 타입은 1바이트 사용, 문자와 정수, -128 ~ 127까지 값만 허용 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /2장/2-20.js: -------------------------------------------------------------------------------- 1 | // 배틀크루저의 체력 2 | const BATTLE_CRUISER = { 3 | MAX_HP: 500, 4 | SIZE: "대형", 5 | }; 6 | // 가지고 있는 미네랄 자원 7 | const MY_MINERAL = 500; 8 | // 가지고 있는 가스 자원 9 | const MY_GAS = 500; 10 | const units = [ 11 | { 12 | name: "드라군", 13 | mineral: 125, 14 | gas: 50, 15 | attackSpeed: 1.25, 16 | damage: 20, 17 | type: "폭발형", 18 | }, 19 | { 20 | name: "마린", 21 | mineral: 50, 22 | gas: 0, 23 | attackSpeed: 0.625, 24 | damage: 6, 25 | type: "일반형", 26 | }, 27 | { 28 | name: "골리앗", 29 | mineral: 100, 30 | gas: 50, 31 | attackSpeed: 0.916, 32 | damage: 20, 33 | type: "폭발형", 34 | }, 35 | { 36 | name: "스카웃", 37 | mineral: 275, 38 | gas: 125, 39 | attackSpeed: 0.916, 40 | damage: 28, 41 | type: " 폭발형 ", 42 | }, 43 | { 44 | name: "뮤탈리스크", 45 | mineral: 100, 46 | gas: 100, 47 | attackSpeed: 1.25, 48 | damage: 9, 49 | type: "일반형", 50 | }, 51 | { 52 | name: "히드라리스크", 53 | mineral: 75, 54 | gas: 25, 55 | attackSpeed: 0.625, 56 | damage: 10, 57 | type: "폭발형", 58 | }, 59 | ]; 60 | -------------------------------------------------------------------------------- /2장/2-21.js: -------------------------------------------------------------------------------- 1 | const MY_MINERAL = 500; 2 | const MY_GAS = 500; 3 | function unitsCanBeProduced(unit) { 4 | const mineralBased = Math.floor(MY_MINERAL / unit.mineral); 5 | const gasBased = Math.floor(MY_GAS / unit.gas); 6 | return Math.min(mineralBased, gasBased); 7 | } 8 | -------------------------------------------------------------------------------- /2장/2-22.js: -------------------------------------------------------------------------------- 1 | function damageCalculator(unit, target) { 2 | const damageTypes = { 3 | 일반형: { 대형: 1, 중형: 1, 소형: 1 }, 4 | 진동형: { 대형: 0.25, 중형: 0.5, 소형: 1 }, 5 | 폭발형: { 대형: 1, 중형: 0.75, 소형: 0.5 }, 6 | }; 7 | return unit.damage * damageTypes[unit.type][target.SIZE]; 8 | } 9 | -------------------------------------------------------------------------------- /2장/2-23.js: -------------------------------------------------------------------------------- 1 | function timeToKill(unit, target) { 2 | const unitsProduced = unitsCanBeProduced(unit); 3 | const damagePerAttack = unitsProduced * damageCalculator(unit, target); 4 | return (target.MAX_HP / damagePerAttack) * unit.attackSpeed; 5 | } 6 | -------------------------------------------------------------------------------- /2장/2-24.js: -------------------------------------------------------------------------------- 1 | // 배틀크루저의 체력 2 | const BATTLE_CRUISER = { 3 | MAX_HP: 500, 4 | SIZE: "대형", 5 | }; 6 | // 가지고 있는 미네랄 자원 7 | const MY_MINERAL = 500; 8 | // 가지고 있는 가스 자원 9 | const MY_GAS = 500; 10 | const units = [ 11 | { 12 | name: "드라군", 13 | mineral: 125, 14 | gas: 50, 15 | attackSpeed: 1.25, 16 | damage: 20, 17 | type: "폭발형", 18 | }, 19 | { 20 | name: "마린", 21 | mineral: 50, 22 | gas: 0, 23 | attackSpeed: 0.625, 24 | damage: 6, 25 | type: "일반형", 26 | }, 27 | { 28 | name: "골리앗", 29 | mineral: 100, 30 | gas: 50, 31 | attackSpeed: 0.916, 32 | damage: 20, 33 | type: "폭발형", 34 | }, 35 | { 36 | name: "스카웃", 37 | mineral: 275, 38 | gas: 125, 39 | attackSpeed: 0.916, 40 | damage: 28, 41 | type: "폭발형", 42 | }, 43 | { 44 | name: "뮤탈리스크", 45 | mineral: 100, 46 | gas: 100, 47 | attackSpeed: 1.25, 48 | damage: 9, 49 | type: "일반형", 50 | }, 51 | { 52 | name: "히드라리스크", 53 | mineral: 75, 54 | gas: 25, 55 | attackSpeed: 0.625, 56 | damage: 10, 57 | type: "폭발형", 58 | }, 59 | ]; 60 | function unitsCanBeProduced(unit) { 61 | const mineralBased = Math.floor(MY_MINERAL / unit.mineral); 62 | const gasBased = Math.floor(MY_GAS / unit.gas); 63 | return Math.min(mineralBased, gasBased); 64 | } 65 | function damageCalculator(unit, target) { 66 | const damageTypes = { 67 | 일반형: { 대형: 1, 중형: 1, 소형: 1 }, 68 | 진동형: { 대형: 0.25, 중형: 0.5, 소형: 1 }, 69 | 폭발형: { 대형: 1, 중형: 0.75, 소형: 0.5 }, 70 | }; 71 | return unit.damage * damageTypes[unit.type][target.SIZE]; 72 | } 73 | function timeToKill(unit, target) { 74 | const unitsProduced = unitsCanBeProduced(unit); 75 | const damagePerAttack = unitsProduced * damageCalculator(unit, target); 76 | return (target.MAX_HP / damagePerAttack) * unit.attackSpeed; 77 | } 78 | // 삽입 정렬 79 | for (let i = 1; i < units.length; i++) { 80 | let key = units[i]; 81 | let j = i - 1; 82 | while ( 83 | j >= 0 && 84 | timeToKill(units[j], BATTLE_CRUISER) > timeToKill(key, BATTLE_CRUISER) 85 | ) { 86 | units[j + 1] = units[j]; 87 | j = j - 1; 88 | } 89 | units[j + 1] = key; 90 | } 91 | console.log(units); 92 | -------------------------------------------------------------------------------- /2장/2-25.js: -------------------------------------------------------------------------------- 1 | const array1 = [A, B, C]; 2 | const array2 = [D, E, F]; 3 | let tempArray = []; 4 | -------------------------------------------------------------------------------- /2장/2-26.js: -------------------------------------------------------------------------------- 1 | const array1 = [5, 7, 9, 42, 87, 124, 168]; 2 | const array2 = [3, 6, 19, 29, 38, 54, 197]; 3 | -------------------------------------------------------------------------------- /2장/2-27.js: -------------------------------------------------------------------------------- 1 | function mergeSort(arr) { 2 | if (arr.length <= 1) { 3 | return arr; 4 | } 5 | const mid = Math.floor(arr.length / 2); // 중간 인덱스 찾기 6 | const left = arr.slice(0, mid); // 중간 원소보다 작은 값이 모인 배열 7 | const right = arr.slice(mid); // 중간 원소보다 큰 값이 모인 배열 8 | const sortedLeft = mergeSort(left); 9 | const sortedRight = mergeSort(right); 10 | return merge(sortedLeft, sortedRight); 11 | } 12 | 13 | function merge(left, right) { 14 | let merged = []; 15 | let leftIndex = 0; 16 | let rightIndex = 0; 17 | while (leftIndex < left.length && rightIndex < right.length) { 18 | if (left[leftIndex] < right[rightIndex]) { 19 | merged.push(left[leftIndex]); 20 | leftIndex++; 21 | } else { 22 | merged.push(right[rightIndex]); 23 | rightIndex++; 24 | } 25 | } 26 | while (leftIndex < left.length) { 27 | merged.push(left[leftIndex]); 28 | leftIndex++; 29 | } 30 | while (rightIndex < right.length) { 31 | merged.push(right[rightIndex]); 32 | rightIndex++; 33 | } 34 | return merged; 35 | } 36 | 37 | // 예시 38 | const array = [5, 9, 2, 8, 11, 5]; 39 | const sortedArray = mergeSort(array); -------------------------------------------------------------------------------- /2장/2-28.js: -------------------------------------------------------------------------------- 1 | // VIP들이 원하는 자리 목록 2 | const VIPSeats = ["D5", "A7", "B3", "A1", "D4", "B1", "A2", "D1", "C1", "C5"]; 3 | -------------------------------------------------------------------------------- /2장/2-29.js: -------------------------------------------------------------------------------- 1 | function mergeSort(arr) { 2 | if (arr.length <= 1) { 3 | return arr; 4 | } 5 | const mid = Math.floor(arr.length / 2); 6 | const left = arr.slice(0, mid); 7 | const right = arr.slice(mid); 8 | return merge(mergeSort(left), mergeSort(right)); 9 | } 10 | function merge(left, right) { 11 | let result = []; 12 | let leftIndex = 0; 13 | let rightIndex = 0; 14 | while (leftIndex < left.length && rightIndex < right.length) { 15 | if (left[leftIndex] < right[rightIndex]) { 16 | result.push(left[leftIndex]); 17 | leftIndex++; 18 | } else { 19 | result.push(right[rightIndex]); 20 | rightIndex++; 21 | } 22 | } 23 | return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex)); 24 | } 25 | const VIPSeats = ["D5", "A7", "B3", "A1", "D4", "B1", "A2", "D1", "C1", "C5"]; 26 | console.log(mergeSort(VIPSeats)); 27 | -------------------------------------------------------------------------------- /2장/2-3.js: -------------------------------------------------------------------------------- 1 | const a = [1, 4, 6, 5, 1, 6]; 2 | const sort = (array) => {}; // 임의의 정렬 함수 3 | console.log(sort(a)); // 1, 1, 4, 5, 6, 6 인덱스 순서: [0, 4, 1, 3, 2, 5] 4 | console.log(sort(a)); // 1, 1, 4, 5, 6, 6 인덱스 순서: [4, 0, 1, 3, 2, 5] -------------------------------------------------------------------------------- /2장/2-30.js: -------------------------------------------------------------------------------- 1 | function mergeSort(arr) { 2 | if (arr.length <= 1) { 3 | return arr; 4 | } 5 | const mid = Math.floor(arr.length / 2); 6 | const left = arr.slice(0, mid); 7 | const right = arr.slice(mid); 8 | return merge(mergeSort(left), mergeSort(right)); 9 | } 10 | 11 | // 합병 함수 12 | function merge(left, right) { 13 | let result = []; 14 | let leftIndex = 0; 15 | let rightIndex = 0; 16 | while (leftIndex < left.length && rightIndex < right.length) { 17 | if (left[leftIndex] < right[rightIndex]) { 18 | result.push(left[leftIndex]); 19 | leftIndex++; 20 | } else { 21 | result.push(right[rightIndex]); 22 | rightIndex++; 23 | } 24 | } 25 | return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex)); 26 | } 27 | 28 | // 랜덤한 숫자가 무작위로 설정된 배열 생성 29 | let arr = []; 30 | for (let i = 0; i < 10; i++) { 31 | arr.push(Math.floor(Math.random() * 100) + 1); 32 | } 33 | 34 | // 배열 합병 정렬 35 | let sortedArr = mergeSort(arr); 36 | 37 | // 정렬한 배열을 특정 패턴으로 출력 38 | let lineCount = 1; 39 | let index = 0; 40 | while (index < sortedArr.length) { 41 | let line = ""; 42 | for (let i = 0; i < lineCount; i++) { 43 | if (index < sortedArr.length) { 44 | line += sortedArr[index] + " "; 45 | } else { 46 | line += sortedArr[sortedArr.length - 1] + " "; // 마지막 숫자 출력 47 | } 48 | index++; 49 | } 50 | console.log(`총 ${line}줄`); 51 | lineCount++; 52 | } 53 | -------------------------------------------------------------------------------- /2장/2-31.js: -------------------------------------------------------------------------------- 1 | function quickSort(array) { 2 | if (array.length <= 1) { 3 | return array; 4 | } 5 | const pivot = array[0]; // (1) 피벗으로 첫 번째 원소를 선택 6 | const left = []; 7 | const right = []; 8 | for (let i = 1; i < array.length; i++) { 9 | array[i] < pivot ? left.push(array[i]) : right.push(array[i]); 10 | } 11 | return [...quickSort(left), pivot, ...quickSort(right)]; // (2) 재귀적으로 연산이 끝날 때까지 반복 12 | } 13 | -------------------------------------------------------------------------------- /2장/2-32.js: -------------------------------------------------------------------------------- 1 | const MAX_FOOD_COUNT = 4; // 최대 먹을 수 있는 음식의 수 2 | const PROTEIN_LIST = [5, 15, 22, 36, 46, 48, 59]; // 각 음식의 단백질 함량 3 | const PRICE_LIST = [3000, 4100, 4500, 5000, 5600, 5900]; // 각 음식의 가격 4 | -------------------------------------------------------------------------------- /2장/2-33.js: -------------------------------------------------------------------------------- 1 | const MAX_FOOD_COUNT = 4; // 최대 먹을 수 있는 음식의 수 2 | const PROTEIN_LIST = [5, 15, 22, 36, 46, 48, 59]; // 각 음식의 단백질 함량 3 | const PRICE_LIST = [3000, 4100, 4500, 5000, 5600, 5900]; // 각 음식의 가격 4 | let budget = 15000; // 철수의 예산 5 | // 각 음식의 가격 대비 단백질 함량을 계산 6 | let ratioList = PROTEIN_LIST.map((protein, index) => { 7 | return { 8 | index: index, 9 | ratio: protein / PRICE_LIST[index], 10 | }; 11 | }); 12 | // 퀵 정렬 함수 정의 13 | function quickSort(array, left = 0, right = array.length - 1) { 14 | if (left < right) { 15 | let pivot = partition(array, left, right); 16 | quickSort(array, left, pivot - 1); 17 | quickSort(array, pivot + 1, right); 18 | } 19 | return array; 20 | } 21 | // 피벗 설정 함수 정의 22 | function partition(array, left, right) { 23 | let pivot = array[right].ratio; 24 | let i = left; 25 | for (let j = left; j < right; j++) { 26 | if (array[j].ratio > pivot) { 27 | [array[i], array[j]] = [array[j], array[i]]; 28 | i++; 29 | } 30 | } 31 | [array[i], array[right]] = [array[right], array[i]]; 32 | return i; 33 | } 34 | // 가격 대비 단백질 함량이 높은 음식부터 퀵 정렬 35 | quickSort(ratioList); 36 | let totalProtein = 0; // 총 단백질 함량 37 | let foodCount = 0; // 선택한 음식의 개수 38 | // 예산 내에서 가장 단백질 함량이 높은 음식부터 선택 39 | for (let i = 0; i < ratioList.length; i++) { 40 | if (budget >= PRICE_LIST[ratioList[i].index]) { 41 | budget -= PRICE_LIST[ratioList[i].index]; 42 | totalProtein += PROTEIN_LIST[ratioList[i].index]; 43 | foodCount++; 44 | if (foodCount === MAX_FOOD_COUNT) { 45 | break; 46 | } 47 | } 48 | } 49 | console.log(totalProtein); // 철수가 섭취할 수 있는 최대 단백질 함량, 99 50 | -------------------------------------------------------------------------------- /2장/2-34.js: -------------------------------------------------------------------------------- 1 | // 방문해야하는 층의 배열 2 | let deliveryFloors = [5, 2, 8, 6, 1, 9, 3, 20, 18, 42, 43, 15, 7, 11, 5]; 3 | -------------------------------------------------------------------------------- /2장/2-35.js: -------------------------------------------------------------------------------- 1 | let deliveryFloors = [5, 2, 8, 6, 1, 9, 3, 20, 18, 42, 43, 15, 7, 11, 5]; 2 | 3 | // 10층 이상의 층은 5의 배수로 변환 4 | deliveryFloors = deliveryFloors.map((floor) => 5 | floor >= 10 ? Math.floor(floor / 5) * 5 : floor 6 | ); 7 | 8 | // 중복 층 제거 9 | deliveryFloors = [...new Set(deliveryFloors)]; 10 | 11 | // 퀵 정렬 12 | function quickSort(array) { 13 | if (array.length < 2) { 14 | return array; 15 | } 16 | const pivot = array[0]; 17 | const less = array.slice(1).filter((i) => i <= pivot); 18 | const greater = array.slice(1).filter((i) => i > pivot); 19 | return [...quickSort(less), pivot, ...quickSort(greater)]; 20 | } 21 | 22 | console.log(quickSort(deliveryFloors)); // 오름차순으로 정렬된 층 출력 23 | -------------------------------------------------------------------------------- /2장/2-36.js: -------------------------------------------------------------------------------- 1 | function heapSort(arr) { 2 | // 힙을 구성하는 함수 3 | function buildHeap(arr) { 4 | const len = arr.length; 5 | for (let i = Math.floor(len / 2) - 1; i >= 0; i--) { 6 | heapify(arr, len, i); 7 | } 8 | } 9 | // 힙을 유지하도록 하는 함수 10 | function heapify(arr, len, idx) { 11 | let largest = idx; 12 | const left = 2 * idx + 1; 13 | const right = 2 * idx + 2; 14 | if (left < len && arr[left] > arr[largest]) { 15 | largest = left; 16 | } 17 | if (right < len && arr[right] > arr[largest]) { 18 | largest = right; 19 | } 20 | if (largest !== idx) { 21 | [arr[idx], arr[largest]] = [arr[largest], arr[idx]]; 22 | heapify(arr, len, largest); 23 | } 24 | } 25 | // 정렬을 수행하는 함수 26 | function sort(arr) { 27 | const len = arr.length; 28 | buildHeap(arr); 29 | for (let i = len - 1; i >= 0; i--) { 30 | [arr[0], arr[i]] = [arr[i], arr[0]]; 31 | heapify(arr, i, 0); 32 | } 33 | return arr; 34 | } 35 | return sort(arr); 36 | } 37 | // 예시 38 | const arr = [6, 3, 8, 2, 10, 5]; 39 | const sortedArr = heapSort(arr); 40 | console.log(sortedArr); // [2, 3, 5, 6, 8, 10]; 41 | -------------------------------------------------------------------------------- /2장/2-37.js: -------------------------------------------------------------------------------- 1 | let treasureBoxs = [ 2 | 2, 5, 20, 602, 49, 856, 10, 5, 1, 3 | // ... 4 | 298, 457, 21, 790, 988, 5 | ]; 6 | -------------------------------------------------------------------------------- /2장/2-38.js: -------------------------------------------------------------------------------- 1 | function heapify(arr, n, i) { 2 | let largest = i; 3 | let left = 2 * i + 1; 4 | let right = 2 * i + 2; 5 | if (left < n && arr[left] > arr[largest]) { 6 | largest = left; 7 | } 8 | if (right < n && arr[right] > arr[largest]) { 9 | largest = right; 10 | } 11 | if (largest != i) { 12 | let swap = arr[i]; 13 | arr[i] = arr[largest]; 14 | arr[largest] = swap; 15 | heapify(arr, n, largest); 16 | } 17 | } 18 | function heapSort(arr) { 19 | let n = arr.length; 20 | for (let i = Math.floor(n / 2) - 1; i >= 0; i--) { 21 | heapify(arr, n, i); 22 | } 23 | for (let i = n - 1; i > 0; i--) { 24 | let temp = arr[0]; 25 | arr[0] = arr[i]; 26 | arr[i] = temp; 27 | heapify(arr, i, 0); 28 | } 29 | } 30 | let treasureBoxs = [ 31 | 2, 5, 20, 602, 49, 856, 10, 5, 1, 32 | // ... 33 | 298, 457, 21, 790, 988, 34 | ]; 35 | heapSort(treasureValues); 36 | console.log(treasureValues.reverse()); // 가치가 높은게 0번 인덱스로 오도록! 37 | -------------------------------------------------------------------------------- /2장/2-39.js: -------------------------------------------------------------------------------- 1 | // 총 100가지 도수를 가진 위스키 2 | let whiskeys = [ 3 | 40, 42.5, 45, 50, 55, 60, 65, 4 | ///... , 5 | 70, 75, 80, 85, 90, 95, 100, 6 | ]; 7 | -------------------------------------------------------------------------------- /2장/2-4.js: -------------------------------------------------------------------------------- 1 | function bubbleSort(array) { 2 | for (let i = 0; i < array.length; i++) { 3 | for (let j = 1; j < array.length; j++) { 4 | if (array[j - 1] > array[j]) { 5 | const temp = array[j]; 6 | array[j] = array[j - 1]; 7 | array[j - 1] = temp; 8 | } 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /2장/2-40.js: -------------------------------------------------------------------------------- 1 | function heapify(arr, n, i) { 2 | let largest = i; 3 | let left = 2 * i + 1; 4 | let right = 2 * i + 2; 5 | if (left < n && arr[left] > arr[largest]) { 6 | largest = left; 7 | } 8 | if (right < n && arr[right] > arr[largest]) { 9 | largest = right; 10 | } 11 | if (largest !== i) { 12 | [arr[i], arr[largest]] = [arr[largest], arr[i]]; 13 | heapify(arr, n, largest); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /2장/2-41.js: -------------------------------------------------------------------------------- 1 | let availableTime = 30; 2 | function heapify(arr, n, i) { 3 | let largest = i; 4 | let left = 2 * i + 1; 5 | let right = 2 * i + 2; 6 | if (left < n && arr[left] > arr[largest]) { 7 | largest = left; 8 | } 9 | if (right < n && arr[right] > arr[largest]) { 10 | largest = right; 11 | } 12 | if (largest !== i) { 13 | [arr[i], arr[largest]] = [arr[largest], arr[i]]; 14 | heapify(arr, n, largest); 15 | } 16 | availableTime -= 1; // 시간 감소 17 | } 18 | -------------------------------------------------------------------------------- /2장/2-42.js: -------------------------------------------------------------------------------- 1 | // 랜덤한 위스키 도수를 담고 있는 배열 2 | let whiskeys = Array.from({ length: 100 }, () => Math.random() * 100 + 1); 3 | console.log(`정돈 안된 위스키들: ${whiskeys}`); 4 | 5 | // 바텐더에게 남은 시간 6 | let availableTime = 30; 7 | function heapify(arr, n, i) { 8 | let largest = i; 9 | let left = 2 * i + 1; 10 | let right = 2 * i + 2; 11 | if (left < n && arr[left] > arr[largest]) { 12 | largest = left; 13 | } 14 | if (right < n && arr[right] > arr[largest]) { 15 | largest = right; 16 | } 17 | if (largest !== i) { 18 | [arr[i], arr[largest]] = [arr[largest], arr[i]]; 19 | heapify(arr, n, largest); 20 | } 21 | availableTime -= 1; // 시간 감소 22 | } 23 | let n = whiskeys.length; 24 | // 최댓값 찾기 25 | for (let i = Math.floor(n / 2) - 1; i >= 0; i--) { 26 | heapify(whiskeys, n, i); 27 | if (availableTime <= 0) { 28 | break; 29 | } 30 | } 31 | // 최솟값 찾기 32 | for (let i = Math.floor(n / 2) - 1; i >= 0; i--) { 33 | heapify(whiskeys, n, i); 34 | if (availableTime <= 0) { 35 | break; 36 | } 37 | } 38 | console.log(`급하게 정돈한 위스키: ${whiskeys}`); 39 | console.log(`도수가 가장 높은 위스키: ${whiskeys[0]}`); 40 | console.log(`도수가 가장 낮은 위스키: ${whiskeys[whiskeys.length - 1]}`); 41 | -------------------------------------------------------------------------------- /2장/2-43.js: -------------------------------------------------------------------------------- 1 | // 입력 배열의 최댓값 2 | function findMax(arr) { 3 | let max = arr[0]; 4 | for (let i = 1; i < arr.length; i++) { 5 | if (arr[i] > max) { 6 | max = arr[i]; 7 | } 8 | } 9 | return max; 10 | } 11 | function radixSort(arr) { 12 | const max = findMax(arr); // 입력 배열의 최댓값을 찾음 13 | // 자릿수 별 기수 정렬 14 | function countingSort(arr, exp) { 15 | const count = new Array(10).fill(0); 16 | const output = new Array(arr.length); 17 | for (let i = 0; i < arr.length; i++) { 18 | const digit = Math.floor(arr[i] / exp) % 10; 19 | count[digit]++; 20 | } 21 | for (let i = 1; i < 10; i++) { 22 | count[i] += count[i - 1]; 23 | } 24 | for (let i = arr.length - 1; i >= 0; i--) { 25 | const digit = Math.floor(arr[i] / exp) % 10; 26 | output[count[digit] - 1] = arr[i]; 27 | count[digit]--; 28 | } 29 | for (let i = 0; i < arr.length; i++) { 30 | arr[i] = output[i]; 31 | } 32 | } 33 | // 가장 큰 자릿수부터 시작하여 기수 정렬을 반복적으로 수행하는 함수 34 | function radixSortUtil(arr) { 35 | const len = arr.length; 36 | const maxDigit = Math.floor(Math.log10(max) + 1); // 최대 자릿수 37 | for (let exp = 1; Math.floor(max / exp) > 0; exp *= 10) { 38 | countingSort(arr, exp); 39 | } 40 | } 41 | radixSortUtil(arr); 42 | return arr; 43 | } 44 | -------------------------------------------------------------------------------- /2장/2-44.js: -------------------------------------------------------------------------------- 1 | function radixSort(arr) { 2 | const countingSort = (arr, exp) => { 3 | const output = new Array(arr.length).fill(0); 4 | const count = new Array(10).fill(0); 5 | arr.forEach((num) => { 6 | const digit = Math.floor(num / exp) % 10; 7 | count[digit]++; // 첫번째 순환에서 1의 자리 숫자만 저장 8 | }); 9 | for (let i = 1; i < count.length; i++) { 10 | count[i] += count[i - 1]; 11 | } 12 | for (let i = arr.length - 1; i >= 0; i--) { 13 | const digit = Math.floor(arr[i] / exp) % 10; // 109 > 1의 자리: 9 14 | output[count[digit] - 1] = arr[i]; // count[9]: 6, output[5] = 109 15 | count[digit]--; // count[9]: 6 - 1 = 5 16 | } 17 | output.forEach((num, i) => { 18 | arr[i] = num; 19 | }); 20 | console.log(`${exp}자리수 연산: `, arr); 21 | }; 22 | const max = Math.max(...arr); 23 | const maxDigit = Math.floor(Math.log10(max) + 1); // 최대 자릿값 24 | for (let exp = 1; Math.floor(max / exp) > 0; exp *= 10) { 25 | countingSort(arr, exp); 26 | } 27 | return arr; 28 | } 29 | 30 | console.log(radixSort([25, 37, 1, 7, 109, 599, 2000])); 31 | -------------------------------------------------------------------------------- /2장/2-45.js: -------------------------------------------------------------------------------- 1 | let students = [ 2 | { grade: 1, class: 1, number: 1, studyTime: 120 }, 3 | { grade: 1, class: 1, number: 2, studyTime: 150 }, 4 | { grade: 1, class: 2, number: 1, studyTime: 90 }, 5 | { grade: 1, class: 2, number: 2, studyTime: 130 }, 6 | { grade: 2, class: 1, number: 1, studyTime: 60 }, 7 | { grade: 2, class: 1, number: 2, studyTime: 110 }, 8 | { grade: 2, class: 2, number: 1, studyTime: 100 }, 9 | { grade: 2, class: 2, number: 2, studyTime: 80 }, 10 | { grade: 3, class: 1, number: 1, studyTime: 30 }, 11 | // 끝없는 학생들... 12 | ]; 13 | -------------------------------------------------------------------------------- /2장/2-46.js: -------------------------------------------------------------------------------- 1 | function radixSort(arr, key) { 2 | const maxNum = Math.max(...arr.map((obj) => obj[key])) * 10; 3 | let divisor = 10; 4 | while (divisor < maxNum) { 5 | let buckets = [...Array(10)].map(() => []); 6 | for (let num of arr) { 7 | buckets[Math.floor((num[key] % divisor) / (divisor / 10))].push(num); 8 | } 9 | arr = [].concat.apply([], buckets); 10 | divisor *= 10; 11 | } 12 | return arr; 13 | } 14 | let students = [ 15 | { grade: 1, class: 1, number: 1, studyTime: 120 }, 16 | { grade: 1, class: 1, number: 2, studyTime: 150 }, 17 | { grade: 1, class: 2, number: 1, studyTime: 90 }, 18 | { grade: 1, class: 2, number: 2, studyTime: 130 }, 19 | { grade: 2, class: 1, number: 1, studyTime: 60 }, 20 | { grade: 2, class: 1, number: 2, studyTime: 110 }, 21 | { grade: 2, class: 2, number: 1, studyTime: 100 }, 22 | { grade: 2, class: 2, number: 2, studyTime: 80 }, 23 | { grade: 3, class: 1, number: 1, studyTime: 30 }, 24 | { grade: 3, class: 1, number: 2, studyTime: 90 }, 25 | ]; 26 | console.log(radixSort(students, "studyTime")); 27 | -------------------------------------------------------------------------------- /2장/2-47.js: -------------------------------------------------------------------------------- 1 | // 문자를 숫자로 변환 2 | function convertToNumeric(str) { 3 | const numericArr = []; 4 | for (let i = 0; i < str.length; i++) { 5 | numericArr.push(str.charCodeAt(i)); // (1): 문자열 코드로 변환 6 | } 7 | return numericArr; 8 | } 9 | // 기수 정렬 함수 10 | function radixSortString(arr) { 11 | const maxLen = getMaxStringLength(arr); // 입력 배열에서 가장 긴 문자열의 길이를 구함 12 | for (let i = maxLen - 1; i >= 0; i--) { 13 | countingSortString(arr, i); 14 | } 15 | return arr; 16 | } 17 | // 문자열의 특정 자리수를 기준으로 계수 정렬하는 함수 18 | function countingSortString(arr, pos) { 19 | const output = new Array(arr.length).fill(""); 20 | const count = new Array(256).fill(0); // ASCII 문자 범위에 따라 적절한 크기로 설정 21 | for (let i = 0; i < arr.length; i++) { 22 | const charCode = pos < arr[i].length ? arr[i].charCodeAt(pos) : 0; 23 | count[charCode]++; 24 | } 25 | for (let i = 1; i < count.length; i++) { 26 | count[i] += count[i - 1]; 27 | } 28 | for (let i = arr.length - 1; i >= 0; i--) { 29 | const charCode = pos < arr[i].length ? arr[i].charCodeAt(pos) : 0; 30 | output[count[charCode] - 1] = arr[i]; 31 | count[charCode]--; 32 | } 33 | for (let i = 0; i < arr.length; i++) { 34 | arr[i] = output[i]; 35 | } 36 | } 37 | // 입력 배열에서 가장 긴 문자열의 길이를 구하는 함수 38 | function getMaxStringLength(arr) { 39 | let maxLen = 0; 40 | for (let i = 0; i < arr.length; i++) { 41 | if (arr[i].length > maxLen) { 42 | maxLen = arr[i].length; 43 | } 44 | } 45 | return maxLen; 46 | } 47 | -------------------------------------------------------------------------------- /2장/2-48.js: -------------------------------------------------------------------------------- 1 | const array1 = [5, 7, 2, 9, 6, 13]; 2 | array1.sort(); 3 | console.log(array1); // 결과: [2, 5, 6, 7, 9, 13] 4 | const array2 = ["red", "blue", "yellow", "green"]; 5 | array2.sort(); 6 | console.log(array2); // 결과: ['blue', 'green', 'red', 'yellow'] 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /2장/2-49.js: -------------------------------------------------------------------------------- 1 | const items = [ 2 | { key: "하늘", value: 10 }, 3 | { key: "바람", value: 5 }, 4 | { key: "구름", value: 8 }, // 5, 8, 10 5 | ]; 6 | // value 기준으로 정렬 7 | items.sort((a, b) => { // compareFunction: 비교 함수 8 | if (a.value > b.value) { // a의 인덱스를 b보다 높여주어야 한다 9 | return 1; 10 | } 11 | if (a.value < b.value) { // a의 인덱스를 b보다 작게 만들어주어야 한다 12 | return -1; 13 | } 14 | // a는 b와 같아야 한다 15 | return 0; 16 | }); 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /2장/2-5.js: -------------------------------------------------------------------------------- 1 | function bubbleSort(array) { 2 | array.map((e1) => 3 | array.map((e2, i) => { 4 | if (array[i] > array[i + 1]) { 5 | // 두 값을 비교하고, 스왑합니다 6 | array[i] = array[i + 1]; 7 | array[i + 1] = e2; 8 | } 9 | }) 10 | ); 11 | return array; 12 | } 13 | -------------------------------------------------------------------------------- /2장/2-50.js: -------------------------------------------------------------------------------- 1 | (a, b) => { 2 | if (a.value > b.value) { 3 | return 1; 4 | } 5 | if (a.value < b.value) { 6 | return -1; 7 | } 8 | // a는 b와 같아야 한다 9 | return 0; 10 | }; 11 | -------------------------------------------------------------------------------- /2장/2-51.js: -------------------------------------------------------------------------------- 1 | (a, b) => { 2 | return a.value - b.value; 3 | }; 4 | -------------------------------------------------------------------------------- /2장/2-52.js: -------------------------------------------------------------------------------- 1 | // 내림차순 정렬 2 | function compareDesc(a, b) { 3 | return b - a; 4 | } 5 | 6 | // 절대값 오름차순 정렬 7 | function compareAbs(a, b) { 8 | return Math.abs(a) - Math.abs(b); 9 | } 10 | -------------------------------------------------------------------------------- /2장/2-6.js: -------------------------------------------------------------------------------- 1 | let scores = [ 2 | { name: "철수", score: 85 }, 3 | { name: "영희", score: 92 }, 4 | { name: "민수", score: 88 }, 5 | { name: "혜진", score: 97 }, 6 | { name: "진수", score: 90 }, 7 | ]; 8 | function bubbleSort(arr) { 9 | let len = arr.length; 10 | for (let i = len - 1; i >= 0; i--) { 11 | for (let j = 1; j <= i; j++) { 12 | if (arr[j - 1].score < arr[j].score) { 13 | let temp = arr[j - 1]; 14 | arr[j - 1] = arr[j]; 15 | arr[j] = temp; 16 | } 17 | } 18 | } 19 | return arr; 20 | } 21 | console.log(bubbleSort(scores)); 22 | -------------------------------------------------------------------------------- /2장/2-7.js: -------------------------------------------------------------------------------- 1 | let cards = [ 2 | ["Diamond", 3], 3 | ["Heart", "A"], 4 | ["Clover", "K"], 5 | ["Spade", 7], 6 | ]; 7 | 8 | function convertCardToPoint(card) { 9 | const addtionalPoint = { 10 | Heart: 0, 11 | Diamond: 13, 12 | Clover: 13 * 2, 13 | Spade: 13 * 3, 14 | }; 15 | const charToNumber = { 16 | A: 1, 17 | J: 11, 18 | Q: 12, 19 | K: 13, 20 | }; 21 | return addtionalPoint[card[0]] + typeof card[1] === "number" 22 | ? card[1] 23 | : charToNumber[card[1]]; 24 | } 25 | -------------------------------------------------------------------------------- /2장/2-8.js: -------------------------------------------------------------------------------- 1 | let cards = [ 2 | ["Diamond", 3], 3 | ["Heart", "A"], 4 | ["Clover", "K"], 5 | ["Spade", 7], 6 | ]; 7 | 8 | function convertToPoint(card) { 9 | const additionalPoint = { 10 | Heart: 0, 11 | Diamond: 13, 12 | Clover: 13 * 2, 13 | Spade: 13 * 3, 14 | }; 15 | const charToNumber = { 16 | A: 1, 17 | J: 11, 18 | Q: 12, 19 | K: 13, 20 | }; 21 | return additionalPoint[card[0]] + (typeof card[1] === "number" ? card[1] : charToNumber[card[1]]); 22 | } 23 | 24 | function bubbleSort(array) { 25 | const n = array.length; 26 | for (let i = 0; i < n - 1; i++) { 27 | for (let j = 0; j < n - i - 1; j++) { 28 | if (convertToPoint(array[j]) > convertToPoint(array[j + 1])) { 29 | // Swap elements 30 | [array[j], array[j + 1]] = [array[j + 1], array[j]]; 31 | } 32 | } 33 | } 34 | return array; 35 | } 36 | 37 | console.log(bubbleSort(cards)); 38 | -------------------------------------------------------------------------------- /2장/2-9.js: -------------------------------------------------------------------------------- 1 | let restaurants = [ 2 | { 3 | name: "음식점A", 4 | totalOrders: 300, 5 | avgRating: 4.5, 6 | likes: 200, 7 | distance: 5, 8 | }, 9 | { 10 | name: "음식점B", 11 | totalOrders: 250, 12 | avgRating: 4.2, 13 | likes: 180, 14 | distance: 25, 15 | }, 16 | { 17 | name: "음식점C", 18 | totalOrders: 400, 19 | avgRating: 4.7, 20 | likes: 250, 21 | distance: 15, 22 | }, 23 | { 24 | name: "음식점D", 25 | totalOrders: 200, 26 | avgRating: 4.1, 27 | likes: 150, 28 | distance: 30, 29 | }, 30 | { 31 | name: "음식점E", 32 | totalOrders: 350, 33 | avgRating: 4.4, 34 | likes: 220, 35 | distance: 10, 36 | }, 37 | ]; 38 | const weights = { totalOrders: 0.2, avgRating: 0.3, likes: 0.2, distance: 0.3 }; 39 | function calculateScore(restaurant) { 40 | const maxDistance = 20; 41 | if (restaurant.distance > maxDistance) { 42 | return null; 43 | } 44 | let score = 45 | weights.totalOrders * restaurant.totalOrders + 46 | weights.avgRating * restaurant.avgRating + 47 | weights.likes * restaurant.likes + 48 | weights.distance * (maxDistance - restaurant.distance); 49 | return score; 50 | } 51 | function bubbleSort(arr) { 52 | let len = arr.length; 53 | for (let i = len - 1; i >= 0; i--) { 54 | for (let j = 1; j <= i; j++) { 55 | let score1 = calculateScore(arr[j - 1]); 56 | let score2 = calculateScore(arr[j]); 57 | if (score1 < score2) { 58 | let temp = arr[j - 1]; 59 | arr[j - 1] = arr[j]; 60 | arr[j] = temp; 61 | } 62 | } 63 | } 64 | return arr; 65 | } 66 | console.log(bubbleSort(restaurants)); 67 | -------------------------------------------------------------------------------- /3장/3-1.js: -------------------------------------------------------------------------------- 1 | const dictionary = [ 2 | { 3 | word: "a", 4 | mean: "라틴 문자의 첫번째 글자", 5 | }, 6 | // ... 7 | ]; 8 | 9 | function findMean(keyword, array) { 10 | for (let i = 0; i < array.length; i++) { 11 | if (array[i].word === keyword) { 12 | return array[i].mean; 13 | } 14 | } 15 | return "단어를 찾지 못했습니다."; 16 | } 17 | 18 | console.log(findMean("a", dictionary)); 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /3장/3-10.js: -------------------------------------------------------------------------------- 1 | let CLASSROOMS = [4, 7, 2, 5, 10, 13]; 2 | let FLOWER_TREES = 3; 3 | -------------------------------------------------------------------------------- /3장/3-11.js: -------------------------------------------------------------------------------- 1 | let CLASSROOMS = [4, 7, 2, 5, 10, 13]; 2 | let FLOWER_TREES = 3; 3 | 4 | CLASSROOMS.sort((a, b) => a - b); 5 | 6 | let start = CLASSROOMS[0]; // 왼쪽 끝 교실 7 | let end = CLASSROOMS[CLASSROOMS.length - 1]; //(오른쪽 끝 교실) 8 | 9 | let result = 0; 10 | 11 | while (start <= end) { 12 | let mid = Math.floor((start + end) / 2); 13 | let value = CLASSROOMS[0]; 14 | let count = 1; 15 | 16 | for (let i = 1; i < CLASSROOMS.length; i++) { 17 | if (CLASSROOMS[i] - value >= mid) { 18 | value = CLASSROOMS[i]; 19 | count++; 20 | } 21 | } 22 | 23 | if (count >= FLOWER_TREES) { 24 | result = mid; 25 | start = mid + 1; 26 | } else { 27 | end = mid - 1; 28 | } 29 | } 30 | 31 | let treePositions = [CLASSROOMS[0]]; 32 | let lastPosition = CLASSROOMS[0]; 33 | 34 | for (let i = 1; i < CLASSROOMS.length; i++) { 35 | if (CLASSROOMS[i] - lastPosition >= result) { 36 | treePositions.push(CLASSROOMS[i]); 37 | lastPosition = CLASSROOMS[i]; 38 | } 39 | } 40 | 41 | console.log(treePositions); 42 | -------------------------------------------------------------------------------- /3장/3-12.js: -------------------------------------------------------------------------------- 1 | let CLASSROOMS = [0, 4, 7, 2, 5, 20, 15, 10, 13]; 2 | let FLOWER_TREES = 4; 3 | -------------------------------------------------------------------------------- /3장/3-13.js: -------------------------------------------------------------------------------- 1 | // 그래프 데이터를 생성하는 클래스 2 | class SeoulGraph { 3 | constructor() { 4 | this.adjList = new Map(); // (1): 인접한 지역을 저장 5 | } 6 | 7 | // 각 지역(정점)을 추가하는 메서드 8 | addVertex(vertex) { 9 | if (!this.adjList.has(vertex)) { 10 | this.adjList.set(vertex, []); 11 | } 12 | } 13 | 14 | // 간선을 추가하는 메서드 15 | addEdge(vertex1, vertex2) { 16 | this.adjList.get(vertex1).push(vertex2); 17 | this.adjList.get(vertex2).push(vertex1); 18 | } 19 | 20 | // DFS 수행하는 메서드 21 | dfs(startVertex) { 22 | const visited = new Set(); // 방문한 지역이 저장되는 Set 타입 데이터 23 | 24 | // DFS 함수 25 | const dfsRecursive = (vertex) => { 26 | visited.add(vertex); 27 | console.log(vertex); 28 | 29 | const neighbors = this.adjList.get(vertex); 30 | 31 | for (const neighbor of neighbors) { 32 | if (!visited.has(neighbor)) { 33 | dfsRecursive(neighbor); 34 | } 35 | } 36 | }; 37 | 38 | dfsRecursive(startVertex); 39 | } 40 | } 41 | 42 | const graph = new SeoulGraph(); // (2) 클래스 생성 43 | graph.addVertex("강남구"); 44 | graph.addVertex("강동구"); 45 | graph.addVertex("강북구"); 46 | /// 이하 생략 ... 47 | 48 | graph.addEdge("강남구", "서초구"); 49 | graph.addEdge("강남구", "용산구"); 50 | graph.addEdge("강남구", "성동구"); 51 | graph.addEdge("강남구", "광진구"); 52 | graph.addEdge("강남구", "송파구"); 53 | 54 | graph.addEdge("강동구", "광진구"); 55 | graph.addEdge("강동구", "송파구"); 56 | /// 이하 생략 ... 57 | 58 | graph.dfs("강남구"); // (3) DFS 실행 59 | -------------------------------------------------------------------------------- /3장/3-14.js: -------------------------------------------------------------------------------- 1 | let maze = [ 2 | ["S", 0, 1, 0, 0], 3 | [0, 0, 0, 0, 0], 4 | [0, 1, 1, 1, 1], 5 | [0, 0, 0, 0, "E"], 6 | [1, 1, 1, 0, 1], 7 | ]; 8 | -------------------------------------------------------------------------------- /3장/3-15.js: -------------------------------------------------------------------------------- 1 | let maze = [ 2 | ["S", 0, 1, 0, 0], 3 | [0, 0, 0, 0, 0], 4 | [0, 1, 1, 1, 1], 5 | [0, 0, 0, 0, "E"], 6 | [1, 1, 1, 0, 1], 7 | ]; 8 | 9 | function dfs(maze, position = [0, 0], path = []) { 10 | let [x, y] = position; 11 | if (maze[x][y] === "E") return [...path, position]; 12 | 13 | let directions = [ 14 | [0, 1], 15 | [0, -1], 16 | [1, 0], 17 | [-1, 0], 18 | ]; 19 | for (let [dx, dy] of directions) { 20 | let newX = x + dx, 21 | newY = y + dy; 22 | if ( 23 | newX >= 0 && 24 | newX < maze.length && 25 | newY >= 0 && 26 | newY < maze[0].length && 27 | (maze[newX][newY] === 0 || maze[newX][newY] === "E") 28 | ) { 29 | maze[x][y] = 1; // 방문한 곳을 표시 30 | let result = dfs(maze, [newX, newY], [...path, position]); 31 | if (result) return result; 32 | } 33 | } 34 | return null; 35 | } 36 | 37 | console.log(dfs(maze)); 38 | -------------------------------------------------------------------------------- /3장/3-16.js: -------------------------------------------------------------------------------- 1 | let map = [ 2 | [1, 1, 0, 0, 0], 3 | [1, 1, 0, 0, 0], 4 | [0, 0, 1, 0, 1], 5 | [0, 0, 0, 1, 1], 6 | [0, 0, 0, 0, 0], 7 | ]; 8 | -------------------------------------------------------------------------------- /3장/3-17.js: -------------------------------------------------------------------------------- 1 | let map = [ 2 | [1, 1, 0, 0, 0], 3 | [1, 1, 0, 0, 0], 4 | [0, 0, 1, 0, 1], 5 | [0, 0, 0, 1, 1], 6 | [0, 0, 0, 0, 0], 7 | ]; 8 | -------------------------------------------------------------------------------- /3장/3-18.js: -------------------------------------------------------------------------------- 1 | let map = [ 2 | [1, 1, 0, 0, 0], 3 | [1, 1, 0, 0, 0], 4 | [0, 0, 1, 0, 0], 5 | [0, 0, 0, 1, 1], 6 | [0, 0, 0, 0, 0], 7 | ]; 8 | 9 | function dfs(grid, i, j) { 10 | if ( 11 | i < 0 || 12 | j < 0 || 13 | i >= grid.length || 14 | j >= grid[0].length || 15 | grid[i][j] === 0 16 | ) { 17 | return; 18 | } 19 | 20 | grid[i][j] = 0; // 방문한 곳을 표시 21 | 22 | dfs(grid, i + 1, j); 23 | dfs(grid, i - 1, j); 24 | dfs(grid, i, j + 1); 25 | dfs(grid, i, j - 1); 26 | } 27 | 28 | function countIslands(grid) { 29 | let count = 0; 30 | 31 | for (let i = 0; i < grid.length; i++) { 32 | for (let j = 0; j < grid[0].length; j++) { 33 | if (grid[i][j] === 1) { 34 | dfs(grid, i, j); 35 | count++; 36 | } 37 | } 38 | } 39 | 40 | return count; 41 | } 42 | 43 | console.log(countIslands(map)); // 출력 결과: 3 44 | -------------------------------------------------------------------------------- /3장/3-19.js: -------------------------------------------------------------------------------- 1 | let connections = [ 2 | [1, 2], 3 | [1, 3], 4 | [2, 3], 5 | [3, 4], 6 | [5, 6], 7 | ]; 8 | -------------------------------------------------------------------------------- /3장/3-2.js: -------------------------------------------------------------------------------- 1 | const dictionary = [ 2 | { 3 | word: "a", 4 | mean: "라틴 문자의 첫번째 글자", 5 | }, 6 | // ... 7 | ]; 8 | 9 | const result = dictionary.find((el) => el.word === "검색어"); 10 | -------------------------------------------------------------------------------- /3장/3-20.js: -------------------------------------------------------------------------------- 1 | let connections = [ 2 | [1, 2], 3 | [1, 3], 4 | [2, 3], 5 | [3, 4], 6 | [5, 6], 7 | ]; 8 | 9 | function dfs(node, graph, visited) { 10 | visited[node] = true; 11 | 12 | for (let nextNode of graph[node]) { 13 | if (!visited[nextNode]) { 14 | dfs(nextNode, graph, visited); 15 | } 16 | } 17 | } 18 | 19 | function countNetworks(connections) { 20 | let graph = {}; 21 | let visited = {}; 22 | let count = 0; 23 | 24 | for (let [node1, node2] of connections) { 25 | if (!graph[node1]) graph[node1] = []; 26 | if (!graph[node2]) graph[node2] = []; 27 | graph[node1].push(node2); 28 | graph[node2].push(node1); 29 | visited[node1] = false; 30 | visited[node2] = false; 31 | } 32 | 33 | for (let node in graph) { 34 | if (!visited[node]) { 35 | dfs(node, graph, visited); 36 | count++; 37 | } 38 | } 39 | 40 | return count; 41 | } 42 | 43 | console.log(countNetworks(connections)); // 출력 결과: 2 44 | -------------------------------------------------------------------------------- /3장/3-21.js: -------------------------------------------------------------------------------- 1 | // 그래프를 표현한 인접 리스트 2 | const graph = { 3 | A: ["B", "C"], 4 | B: ["A", "D"], 5 | C: ["A", "E", "F"], 6 | D: ["B"], 7 | E: ["C", "G"], 8 | F: ["C", "E"], 9 | G: ["E", "H"], 10 | H: ["G"], 11 | }; 12 | 13 | // 너비 우선 탐색 14 | function bfs(graph, startNode) { 15 | const visited = {}; // 방문한 정점을 저장할 객체 16 | const queue = []; // 탐색할 정점을 저장할 큐 17 | 18 | visited[startNode] = true; // 시작 정점을 방문 처리 19 | queue.push(startNode); // 시작 정점을 큐에 추가 20 | 21 | while (queue.length > 0) { 22 | const node = queue.shift(); // 큐에서 정점을 하나씩 추출 23 | 24 | console.log(node); // 정점 출력 (또는 원하는 작업 수행) 25 | 26 | const adjacentNodes = graph[node]; // 인접한 정점들을 가져옴 27 | for (let i = 0; i < adjacentNodes.length; i++) { 28 | const adjacentNode = adjacentNodes[i]; 29 | if (!visited[adjacentNode]) { 30 | // 방문하지 않은 정점인 경우 31 | visited[adjacentNode] = true; // 방문 처리 32 | queue.push(adjacentNode); // 큐에 추가 33 | } 34 | } 35 | } 36 | } 37 | 38 | // BFS 호출 예시 39 | bfs(graph, "A"); 40 | -------------------------------------------------------------------------------- /3장/3-22.js: -------------------------------------------------------------------------------- 1 | // 그래프를 표현한 인접 리스트 2 | const graph = { 3 | A: ["B", "C"], 4 | B: ["A", "D"], 5 | C: ["A", "E", "F"], 6 | D: ["B"], 7 | E: ["C", "G"], 8 | F: ["C", "E"], 9 | G: ["E", "H"], 10 | H: ["G"], 11 | }; 12 | 13 | // 너비 우선 탐색 14 | function bfs(graph, startNode, targetNode) { 15 | const visited = {}; // 방문한 정점을 저장할 객체 16 | const queue = []; // 탐색할 정점을 저장할 큐 17 | const distances = {}; // 시작 정점으로부터의 거리를 저장할 객체 18 | 19 | visited[startNode] = true; // 시작 정점을 방문 처리 20 | queue.push(startNode); // 시작 정점을 큐에 추가 21 | distances[startNode] = 0; // 시작 정점까지의 거리는 0 22 | 23 | while (queue.length > 0) { 24 | const node = queue.shift(); // 큐에서 정점을 하나씩 추출 25 | 26 | if (node === targetNode) { 27 | return distances[node]; // 목표 정점에 도달한 경우 거리 반환 28 | } 29 | 30 | const adjacentNodes = graph[node]; // 인접한 정점들을 가져옴 31 | for (let i = 0; i < adjacentNodes.length; i++) { 32 | const adjacentNode = adjacentNodes[i]; 33 | if (!visited[adjacentNode]) { 34 | // 방문하지 않은 정점인 경우 35 | visited[adjacentNode] = true; // 방문 처리 36 | queue.push(adjacentNode); // 큐에 추가 37 | distances[adjacentNode] = distances[node] + 1; // 거리 업데이트 38 | } 39 | } 40 | } 41 | 42 | return -1; // 탐색 실패 시 -1 반환 43 | } 44 | 45 | // 최단 거리 계산 호출 예시 46 | const shortestDistance = bfs(graph, "A", "B"); 47 | console.log(`A에서 B까지의 최단 거리: ${shortestDistance}`); 48 | -------------------------------------------------------------------------------- /3장/3-23.js: -------------------------------------------------------------------------------- 1 | const korean = [ 2 | { 3 | 이름: "이소영", 4 | 주민등록번호: "990825-2305941", 5 | 친구: ["990412-1450372", "970501-2295043"], 6 | }, 7 | ]; 8 | -------------------------------------------------------------------------------- /3장/3-24.js: -------------------------------------------------------------------------------- 1 | const korean = [ 2 | { 3 | 이름: "이소영", 4 | 주민등록번호: "990825-2305941", 5 | 친구: ["990412-1450372", "970501-2295043", "850410-1928392" /* ... */], 6 | }, 7 | { 8 | 이름: "박소정", 9 | 주민등록번호: "850410-1928392", 10 | 친구: ["990825-2305941"], 11 | } 12 | // ... 다른 사용자 정보들 ... 13 | ]; 14 | 15 | function findFriendOfFriendBFS(name, targetBirthdate) { 16 | const visited = new Set(); 17 | const queue = []; 18 | 19 | // 이소영을 큐에 추가 20 | queue.push({ 21 | person: korean.find((person) => person.이름 === name), 22 | depth: 0, 23 | }); 24 | 25 | while (queue.length !== 0) { 26 | const { person, depth } = queue.shift(); 27 | 28 | if (person) { 29 | // 현재 사용자의 친구 목록을 확인 30 | for (const friendId of person.친구) { 31 | const friend = korean.find((p) => p.주민등록번호 === friendId); 32 | 33 | if (friend && !visited.has(friendId)) { 34 | visited.add(friendId); 35 | 36 | // 생일을 기준으로 최인기 찾기 37 | if (friend.주민등록번호.startsWith(targetBirthdate)) { 38 | return friend; 39 | } 40 | 41 | // 친구의 친구를 큐에 추가 42 | queue.push({ person: friend, depth: depth + 1 }); 43 | } 44 | } 45 | } 46 | } 47 | 48 | return null; // 찾지 못한 경우 49 | } 50 | 51 | // 이소영의 친구의 친구 중 생일이 1985년 4월 10일인 사용자 찾기 52 | const resultBFS = findFriendOfFriendBFS("이소영", "850410"); 53 | console.log(resultBFS); 54 | 55 | // 최인기라는 이름을 찾는 코드는 여러분이 추가해보세요! 56 | -------------------------------------------------------------------------------- /3장/3-25.js: -------------------------------------------------------------------------------- 1 | let peaks = [ 2 | { 3 | name: "A", 4 | connections: [ 5 | { peak: "B", difficulty: 3 }, 6 | { peak: "C", difficulty: 1 }, 7 | ], 8 | }, 9 | { 10 | name: "B", 11 | connections: [ 12 | { peak: "A", difficulty: 3 }, 13 | { peak: "C", difficulty: 2 }, 14 | { peak: "D", difficulty: 5 }, 15 | ], 16 | }, 17 | { 18 | name: "C", 19 | connections: [ 20 | { peak: "A", difficulty: 1 }, 21 | { peak: "B", difficulty: 2 }, 22 | { peak: "D", difficulty: 4 }, 23 | ], 24 | }, 25 | { 26 | name: "D", 27 | connections: [ 28 | { peak: "B", difficulty: 6 }, 29 | { peak: "C", difficulty: 4 }, 30 | ], 31 | }, 32 | ]; 33 | -------------------------------------------------------------------------------- /3장/3-26.js: -------------------------------------------------------------------------------- 1 | let peaks = [ 2 | { 3 | name: "A", 4 | connections: [ 5 | { peak: "B", difficulty: 3 }, 6 | { peak: "C", difficulty: 1 }, 7 | ], 8 | }, 9 | { 10 | name: "B", 11 | connections: [ 12 | { peak: "A", difficulty: 3 }, 13 | { peak: "C", difficulty: 2 }, 14 | { peak: "D", difficulty: 5 }, 15 | ], 16 | }, 17 | { 18 | name: "C", 19 | connections: [ 20 | { peak: "A", difficulty: 1 }, 21 | { peak: "B", difficulty: 2 }, 22 | { peak: "D", difficulty: 4 }, 23 | ], 24 | }, 25 | { 26 | name: "D", 27 | connections: [ 28 | { peak: "B", difficulty: 6 }, 29 | { peak: "C", difficulty: 4 }, 30 | ], 31 | }, 32 | ]; 33 | 34 | function getPaths(graph, start, end, visited = [], paths = []) { 35 | visited.push(start); 36 | if (start === end) { 37 | paths.push([...visited]); 38 | } else { 39 | for (let node in graph[start]) { 40 | if (!visited.includes(node)) { 41 | getPaths(graph, node, end, visited, paths); 42 | } 43 | } 44 | } 45 | visited.pop(); 46 | return paths; 47 | } 48 | 49 | function getDifficulty(graph, path) { 50 | let difficulty = 0; 51 | for (let i = 0; i < path.length - 1; i++) { 52 | difficulty += graph[path[i]][path[i + 1]]; 53 | } 54 | return difficulty; 55 | } 56 | 57 | function getPermutations(array) { 58 | let results = []; 59 | 60 | if (array.length === 1) { 61 | results.push(array); 62 | return results; 63 | } 64 | 65 | for (let i = 0; i < array.length; i++) { 66 | let firstChar = array[i]; 67 | let charsLeft = array.slice(0, i).concat(array.slice(i + 1)); 68 | let innerPermutations = getPermutations(charsLeft); 69 | for (let j = 0; j < innerPermutations.length; j++) { 70 | results.push([firstChar].concat(innerPermutations[j])); 71 | } 72 | } 73 | return results; 74 | } 75 | 76 | function createGraph(peaks) { 77 | const graph = {}; 78 | 79 | peaks.forEach((peak) => { 80 | graph[peak.name] = {}; 81 | 82 | peak.connections.forEach((connection) => { 83 | graph[peak.name][connection.peak] = connection.difficulty; 84 | }); 85 | }); 86 | 87 | return graph; 88 | } 89 | 90 | function findPath(peaks, start) { 91 | const graph = createGraph(peaks); 92 | let minDifficulty = Infinity; 93 | let minPath; 94 | const nodes = Object.keys(graph); 95 | nodes.splice(nodes.indexOf(start), 1); 96 | 97 | const permutations = getPermutations(nodes); 98 | permutations.forEach((permutation) => { 99 | const path = [start, ...permutation, start]; 100 | const difficulty = getDifficulty(graph, path); 101 | if (difficulty < minDifficulty) { 102 | minDifficulty = difficulty; 103 | minPath = path; 104 | } 105 | }); 106 | 107 | return { path: minPath, difficulty: minDifficulty }; 108 | } 109 | 110 | console.log(findPath(peaks, "A")); 111 | -------------------------------------------------------------------------------- /3장/3-27.js: -------------------------------------------------------------------------------- 1 | class PriorityQueue { 2 | constructor() { 3 | this.queue = []; 4 | } 5 | 6 | enqueue(node, cost) { 7 | this.queue.push({ node, cost }); 8 | this.queue.sort((a, b) => a.cost - b.cost); 9 | } 10 | 11 | dequeue() { 12 | return this.queue.shift(); 13 | } 14 | } 15 | 16 | function createGraph(peaks) { 17 | const graph = {}; 18 | 19 | peaks.forEach((peak) => { 20 | graph[peak.name] = {}; 21 | 22 | peak.connections.forEach((connection) => { 23 | graph[peak.name][connection.peak] = connection.difficulty; 24 | }); 25 | }); 26 | 27 | return graph; 28 | } 29 | 30 | function dijkstra(peaks, start) { 31 | const graph = createGraph(peaks); 32 | const costs = {}; 33 | const parents = {}; 34 | const processed = []; 35 | const queue = new PriorityQueue(); 36 | 37 | costs[start] = 0; 38 | queue.enqueue(start, 0); 39 | 40 | while (queue.queue.length > 0) { 41 | const { node: lowestNode } = queue.dequeue(); 42 | 43 | if (!processed.includes(lowestNode)) { 44 | processed.push(lowestNode); 45 | 46 | Object.keys(graph[lowestNode]).forEach((neighbor) => { 47 | const newCost = costs[lowestNode] + graph[lowestNode][neighbor]; 48 | 49 | if (!costs[neighbor] || costs[neighbor] > newCost) { 50 | costs[neighbor] = newCost; 51 | parents[neighbor] = lowestNode; 52 | queue.enqueue(neighbor, newCost); 53 | } 54 | }); 55 | } 56 | } 57 | 58 | return { costs, parents }; 59 | } 60 | 61 | let peaks = [ 62 | { 63 | name: "A", 64 | connections: [ 65 | { peak: "B", difficulty: 3 }, 66 | { peak: "C", difficulty: 1 }, 67 | ], 68 | }, 69 | { 70 | name: "B", 71 | connections: [ 72 | { peak: "A", difficulty: 3 }, 73 | { peak: "C", difficulty: 2 }, 74 | { peak: "D", difficulty: 5 }, 75 | ], 76 | }, 77 | { 78 | name: "C", 79 | connections: [ 80 | { peak: "A", difficulty: 1 }, 81 | { peak: "B", difficulty: 2 }, 82 | { peak: "D", difficulty: 4 }, 83 | ], 84 | }, 85 | { 86 | name: "D", 87 | connections: [ 88 | { peak: "B", difficulty: 6 }, 89 | { peak: "C", difficulty: 4 }, 90 | ], 91 | }, 92 | ]; 93 | 94 | console.log(dijkstra(peaks, "A")); 95 | -------------------------------------------------------------------------------- /3장/3-28.js: -------------------------------------------------------------------------------- 1 | function primMST(graph) { 2 | const parent = []; 3 | const key = []; 4 | const visited = []; 5 | const { length } = graph; 6 | for (let i = 0; i < length; i++) { 7 | // (1) 8 | key[i] = Infinity; 9 | visited[i] = false; 10 | } 11 | key[0] = 0; 12 | parent[0] = -1; 13 | 14 | for (let count = 0; count < length - 1; count++) { 15 | let u = minKey(key, visited); // (2) 16 | visited[u] = true; 17 | for (let v = 0; v < length; v++) { 18 | if (graph[u][v] && visited[v] === false && graph[u][v] < key[v]) { 19 | // (5) 20 | parent[v] = u; 21 | key[v] = graph[u][v]; 22 | } 23 | } 24 | } 25 | return parent; 26 | } 27 | 28 | function minKey(key, visited) { 29 | let min = Infinity; 30 | let minIndex; 31 | for (let v = 0; v < key.length; v++) { 32 | if (visited[v] === false && key[v] < min) { 33 | // (3) 34 | min = key[v]; 35 | minIndex = v; // (4) 36 | } 37 | } 38 | return minIndex; 39 | } 40 | 41 | const graph = [ 42 | [0, 2, 0, 6, 0], 43 | [2, 0, 3, 8, 5], 44 | [0, 3, 0, 0, 7], 45 | [6, 8, 0, 0, 9], 46 | [0, 5, 7, 9, 0], 47 | ]; 48 | 49 | console.log(primMST(graph)); // [ -1, 0, 1, 0, 1 ] 50 | -------------------------------------------------------------------------------- /3장/3-29.js: -------------------------------------------------------------------------------- 1 | function KruskalMST(graph) { 2 | const parent = []; 3 | const rank = []; 4 | let result = []; 5 | let edges = []; 6 | for (let u = 0; u < graph.length; u++) { 7 | for (let v = 0; v < graph.length; v++) { 8 | if (graph[u][v] !== 0) { 9 | edges.push([u, v, graph[u][v]]); 10 | } 11 | } 12 | } 13 | edges.sort((a, b) => a[2] - b[2]); 14 | for (let node = 0; node < graph.length; node++) { 15 | parent[node] = node; 16 | rank[node] = 0; 17 | } 18 | let i = 0; 19 | while (result.length < graph.length - 1) { 20 | let [u, v, w] = edges[i++]; 21 | let x = find(parent, u); 22 | let y = find(parent, v); 23 | if (x !== y) { 24 | union(parent, rank, x, y); 25 | result.push([u, v, w]); 26 | } 27 | } 28 | return result; 29 | } 30 | 31 | function find(parent, node) { 32 | if (parent[node] !== node) { 33 | parent[node] = find(parent, parent[node]); 34 | } 35 | return parent[node]; 36 | } 37 | 38 | function union(parent, rank, x, y) { 39 | if (rank[x] > rank[y]) { 40 | parent[y] = x; 41 | } else if (rank[x] < rank[y]) { 42 | parent[x] = y; 43 | } else { 44 | parent[y] = x; 45 | rank[x]++; 46 | } 47 | } 48 | 49 | const graph = [ 50 | [0, 2, 0, 6, 0], 51 | [2, 0, 3, 8, 5], 52 | [0, 3, 0, 0, 7], 53 | [6, 8, 0, 0, 9], 54 | [0, 5, 7, 9, 0], 55 | ]; 56 | 57 | console.log(logruskalMST(graph)); 58 | 59 | // [ [ 0, 1, 2 ], [ 1, 2, 3 ], [ 1, 4, 5 ], [ 0, 3, 6 ] ] 60 | -------------------------------------------------------------------------------- /3장/3-3.js: -------------------------------------------------------------------------------- 1 | const students = [ 2 | // 1 ~ 9번째 줄 학생 정보 생략... 3 | [ 4 | { name: "철수", shoes: "red" }, 5 | { name: "영희", shoes: "blue" }, 6 | { name: "민수", shoes: "blue" }, 7 | { name: "지민", shoes: "black" }, 8 | { name: "태현", shoes: "blue" }, 9 | { name: "승우", shoes: "green" }, 10 | // ... 나머지 학생 정보 생략 11 | ], 12 | // 11 ~ n번째 줄 학생 정보 생략... 13 | ]; 14 | -------------------------------------------------------------------------------- /3장/3-30.js: -------------------------------------------------------------------------------- 1 | // 각 도시 간 전선 설치 비용을 나타내는 그래프 2 | const graph = [ 3 | [0, 2, 0, 6, 0], 4 | [2, 0, 3, 8, 5], 5 | [0, 3, 0, 0, 7], 6 | [6, 8, 0, 0, 9], 7 | [0, 5, 7, 9, 0], 8 | ]; 9 | const cities = ["Seoul", "Busan", "Daegu", "Incheon", "Gwangju"]; 10 | -------------------------------------------------------------------------------- /3장/3-31.js: -------------------------------------------------------------------------------- 1 | function KruskalMST(graph) { 2 | // ... 앞선 크루스칼 알고리즘의 코드를 이용합니다 ... 3 | } 4 | // 각 도시 간 전선 설치 비용을 나타내는 그래프 5 | const graph = [ 6 | [0, 2, 0, 6, 0], 7 | [2, 0, 3, 8, 5], 8 | [0, 3, 0, 0, 7], 9 | [6, 8, 0, 0, 9], 10 | [0, 5, 7, 9, 0], 11 | ]; 12 | const cities = ["서울", "부산", "대구", "인천", "광주"]; 13 | const result = KruskalMST(graph); 14 | for (let i = 0; i < result.length; i++) { 15 | console.log(`${cities[result[i][0]]} 와 ${cities[result[i][1]]} 전선 연결 비 16 | 용: ${result[i][2]}`); 17 | } 18 | -------------------------------------------------------------------------------- /3장/3-4.js: -------------------------------------------------------------------------------- 1 | function findSuspect(students, row, shoeColor, nameHint) { 2 | const suspects = students[row]; 3 | for (let i = 0; i < suspects.length; i++) { 4 | if ( 5 | suspects[i].shoes === shoeColor && 6 | suspects[i].name.endsWith(nameHint) 7 | ) { 8 | return suspects[i]; 9 | } 10 | } 11 | return null; 12 | } 13 | 14 | const students = [ 15 | // 1 ~ 9번째 줄 학생 정보 생략... 16 | [ 17 | { name: "철수", shoes: "red" }, 18 | { name: "영희", shoes: "blue" }, 19 | { name: "민수", shoes: "blue" }, 20 | { name: "지민", shoes: "black" }, 21 | { name: "태현", shoes: "blue" }, 22 | { name: "승우", shoes: "green" }, 23 | // ... 나머지 학생 정보 생략 24 | ], 25 | // 11 ~ n번째 줄 학생 정보 생략... 26 | ]; 27 | 28 | console.log(findSuspect(students, 9, "blue", "수")); 29 | -------------------------------------------------------------------------------- /3장/3-5.js: -------------------------------------------------------------------------------- 1 | function checkSecretCodes(codes, targets) { 2 | let result = []; 3 | for (let i = 0; i < targets.length; i++) { 4 | let foundIndexes = []; 5 | for (let j = 0; j < codes.length; j++) { 6 | if (codes[j] === targets[i]) { 7 | foundIndexes.push(j); 8 | } 9 | } 10 | result.push(foundIndexes); 11 | } 12 | return result; 13 | } 14 | 15 | let secretCodes = [ 16 | 0, 29, 5, 1, 3, 6, 92, 208, 39, 5, 6, 9, 29, 58, 22, 110, 92, 95, 91, 2, 17 | ]; 18 | let targets = [0, 7, 2, 8, 5]; // 찾아야 하는 비밀 코드 19 | console.log(checkSecretCodes(secretCodes, targets)); 20 | -------------------------------------------------------------------------------- /3장/3-6.js: -------------------------------------------------------------------------------- 1 | function findMines(field, totalMines) { 2 | let foundMines = 0; 3 | let totalCells = field.length * field[0].length; 4 | 5 | for (let i = 0; i < field.length; i++) { 6 | for (let j = 0; j < field[i].length; j++) { 7 | if (field[i][j] === 1) { 8 | foundMines++; 9 | console.log( 10 | `지뢰 발견! 현재 위치: (${i}, ${j}), 남은 지뢰 확률: ${( 11 | (totalMines - foundMines) / 12 | (totalCells - (i * field[i].length + j + 1)) 13 | ).toFixed(2)}` 14 | ); 15 | } 16 | if (foundMines === totalMines) { 17 | console.log("clear"); 18 | return; 19 | } 20 | } 21 | } 22 | } 23 | 24 | let field = [ 25 | [0, 0, 0, 1, 0], 26 | [1, 0, 0, 0, 0], 27 | [0, 1, 0, 0, 0], 28 | [0, 0, 0, 0, 1], 29 | [0, 0, 1, 0, 0], 30 | ]; 31 | 32 | findMines(field, 5); 33 | -------------------------------------------------------------------------------- /3장/3-7.js: -------------------------------------------------------------------------------- 1 | function binarySearch(arr, target) { 2 | let left = 0; 3 | let right = arr.length - 1; 4 | 5 | while (left <= right) { 6 | let mid = Math.floor((left + right) / 2); // 배열의 중간 인덱스 7 | 8 | if (arr[mid] === target) { 9 | return mid; 10 | } else if (arr[mid] < target) { 11 | left = mid + 1; 12 | } else { 13 | right = mid - 1; 14 | } 15 | } 16 | 17 | return -1; // 검색값이 배열에 존재하지 않을 경우 -1을 반환합니다. 18 | } 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /3장/3-8.js: -------------------------------------------------------------------------------- 1 | let bookISBNs = [ 2 | 9788996094050, 9788996094067, 9788996094074, 9788996094081, 9788996094098, 3 | ]; // 서점에 있는 책들의 배열 4 | -------------------------------------------------------------------------------- /3장/3-9.js: -------------------------------------------------------------------------------- 1 | function binarySearch(arr, target) { 2 | let left = 0; 3 | let right = arr.length - 1; 4 | 5 | while (left <= right) { 6 | let mid = Math.floor((left + right) / 2); 7 | 8 | if (arr[mid] === target) { 9 | return mid; 10 | } else if (arr[mid] < target) { 11 | left = mid + 1; 12 | } else { 13 | right = mid - 1; 14 | } 15 | } 16 | 17 | return -1; 18 | } 19 | 20 | let bookISBNs = [ 21 | 9788996094050, 9788996094067, 9788996094074, 9788996094081, 9788996094098, 22 | ]; 23 | console.log(binarySearch(bookISBNs, 9788996094074)); // 책의 위치 인덱스: 2 24 | -------------------------------------------------------------------------------- /4장/4-1.js: -------------------------------------------------------------------------------- 1 | function fibonacciRecursive(n) { 2 | if (n <= 1) { 3 | return n; 4 | } 5 | return fibonacciRecursive(n - 1) + fibonacciRecursive(n - 2); 6 | } 7 | 8 | const n = 1000; 9 | console.log(fibonacciRecursive(1000)); 10 | -------------------------------------------------------------------------------- /4장/4-2.js: -------------------------------------------------------------------------------- 1 | function fibonacci(n) { 2 | const fibValues = [0, 1]; // 배열을 사용해 이미 계산한 값을 저장 3 | 4 | for (let i = 2; i <= n; i++) { 5 | fibValues[i] = fibValues[i - 1] + fibValues[i - 2]; 6 | } 7 | 8 | return fibValues[n]; 9 | } 10 | 11 | const n = 1000; 12 | const fibonacci1000 = fibonacci(n); 13 | console.log(`피보나치 수열의 ${n}번째 값: ${fibonacci1000}`); 14 | -------------------------------------------------------------------------------- /4장/4-3.js: -------------------------------------------------------------------------------- 1 | // 와일드카드 패턴과 매칭되는지 확인하고, true 또는 false를 리턴하는 함수 2 | function isMatch(pattern, text) { 3 | if (pattern.length === 0) { 4 | return text.length === 0; 5 | } 6 | 7 | if (pattern[0] === "*") { 8 | // *인 경우, 0글자부터 text의 길이 매칭 9 | for (let i = 0; i <= text.length; i++) { 10 | if (isMatch(pattern.substring(1), text.substring(i))) { 11 | return true; 12 | } 13 | } 14 | return false; 15 | } else if (pattern[0] === "?") { 16 | // ?인 경우, 텍스트의 현재 글자가 존재하는지 확인 17 | if (text.length === 0) { 18 | return false; 19 | } 20 | return isMatch(pattern.substring(1), text.substring(1)); 21 | } else if (pattern[0] === text[0]) { 22 | // 현재 패턴 문자와 텍스트 문자가 일치하는 경우 다음 문자 비교 23 | return isMatch(pattern.substring(1), text.substring(1)); 24 | } else { 25 | // 일치하지 않는 경우 26 | return false; 27 | } 28 | } 29 | 30 | // 결과 출력 31 | console.log(isMatch("he*o", "hello")); // true 32 | console.log(isMatch("h?", "hi")); // true 33 | console.log(isMatch("f*o", "faa")); // false -------------------------------------------------------------------------------- /4장/4-4.js: -------------------------------------------------------------------------------- 1 | function isMatch(pattern, text) { 2 | const m = pattern.length; 3 | const n = text.length; 4 | 5 | // dp[i][j]는 pattern의 처음 i 글자와 text의 처음 j 글자가 일치하는지를 저장하는 배열 6 | const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(false)); 7 | 8 | // 빈 패턴과 빈 텍스트는 항상 일치 9 | dp[0][0] = true; 10 | 11 | // 패턴이 *로 시작하는 경우에는 빈 텍스트와도 일치하므로 dp[i][0]을 갱신 12 | for (let i = 1; i <= m; i++) { 13 | // (1): m만큼 순회하는 반복문 14 | if (pattern[i - 1] === "*") { 15 | dp[i][0] = dp[i - 1][0]; 16 | } 17 | } 18 | 19 | // 동적 프로그래밍을 통해 dp 배열 갱신 20 | for (let i = 1; i <= m; i++) { 21 | // (2): m과 n만큼 순회하는 중첩 반복문 22 | for (let j = 1; j <= n; j++) { 23 | if (pattern[i - 1] === "*") { 24 | // *인 경우, 이전에도 *이거나 25 | // 현재 문자와 이전 패턴 문자가 일치하는 경우 26 | // 또는 이전 문자열과 일치하는 경우 27 | dp[i][j] = dp[i - 1][j] || dp[i][j - 1] || dp[i - 1][j - 1]; 28 | } else if (pattern[i - 1] === "?" || pattern[i - 1] === text[j - 1]) { 29 | // ?이거나 현재 패턴 문자와 텍스트 문자가 일치하는 경우 30 | dp[i][j] = dp[i - 1][j - 1]; 31 | } 32 | } 33 | } 34 | 35 | // 최종 결과 반환 (pattern의 전체 길이와 text의 전체 길이가 일치하는지 확인) 36 | return dp[m][n]; 37 | } 38 | 39 | // 결과 반환 40 | console.log(isMatch("g*ks", "geeks")); // true 41 | console.log(isMatch("ge?ks*", "geeksforgeeks")); // true 42 | console.log(isMatch("g*k", "gee")); // false 43 | -------------------------------------------------------------------------------- /4장/4-5.js: -------------------------------------------------------------------------------- 1 | function coinChange(coins, amount) { 2 | let dp = new Array(amount + 1).fill(Infinity); 3 | dp[0] = 0; 4 | 5 | for (let coin of coins) { 6 | for (let i = coin; i <= amount; i++) { 7 | dp[i] = Math.min(dp[i], dp[i - coin] + 1); 8 | } 9 | } 10 | 11 | return dp[amount] === Infinity ? -1 : dp[amount]; 12 | } 13 | 14 | console.log(coinChange([1, 2, 5], 11)); // 출력: 3 15 | -------------------------------------------------------------------------------- /4장/4-6.js: -------------------------------------------------------------------------------- 1 | const N = 7; 2 | const gold = [6, 7, 4, 8, 2, 9, 5]; 3 | const tree = [ 4 | [1, 2], // 집 0과 연결된 집들 5 | [0, 3, 4], // 집 1과 연결된 집들 6 | [0, 5, 6], // 집 2와 연결된 집들 7 | [1], // 집 3과 연결된 집들 8 | [1], // 집 4와 연결된 집들 9 | [2], // 집 5와 연결된 집들 10 | [2], // 집 6과 연결된 집들 11 | ]; 12 | const dp = Array.from(Array(N), () => Array(2).fill(0)); 13 | 14 | function dfs(node, parent, tree, gold, dp) { 15 | dp[node][0] = 0; // Node를 포함하지 않는 경우 16 | dp[node][1] = gold[node]; // Node를 포함하는 경우 17 | 18 | for (let neighbor of tree[node]) { 19 | if (neighbor === parent) continue; // 부모 노드는 건너뛰기 20 | dfs(neighbor, node, tree, gold, dp); 21 | dp[node][0] += Math.max(dp[neighbor][0], dp[neighbor][1]); 22 | dp[node][1] += dp[neighbor][0]; 23 | } 24 | } 25 | 26 | function getMaxGold(N, gold, tree) { 27 | const dp = Array.from(Array(N), () => Array(2).fill(0)); 28 | dfs(0, -1, tree, gold, dp); 29 | return Math.max(dp[0][0], dp[0][1]); 30 | } 31 | 32 | console.log(getMaxGold(N, gold, tree)); // 최대 골드 출력 33 | -------------------------------------------------------------------------------- /5장/5-1.js: -------------------------------------------------------------------------------- 1 | function calculateChange(itemPrice, amountPaid) { 2 | let change = amountPaid - itemPrice; 3 | 4 | if (change < 0) { 5 | console.log("지불 금액이 부족합니다."); 6 | return; 7 | } 8 | 9 | const denominations = [50000, 10000, 5000, 1000, 500, 100, 50, 10]; 10 | const changeResult = {}; 11 | 12 | for (const denomination of denominations) { 13 | const count = Math.floor(change / denomination); 14 | 15 | if (count > 0) { 16 | changeResult[denomination] = count; 17 | change -= denomination * count; 18 | } 19 | } 20 | 21 | console.log("잔돈:", changeResult); 22 | } 23 | 24 | // 예시: 35,000원짜리 물건을 50,000원으로 지불했을 때의 잔돈 계산 25 | calculateChange(35000, 50000); 26 | -------------------------------------------------------------------------------- /5장/5-2.js: -------------------------------------------------------------------------------- 1 | function giveChange(itemPrice, amountPaid) { 2 | let change = amountPaid - itemPrice; 3 | 4 | if (change < 0) { 5 | console.log("지불 금액이 부족합니다."); 6 | return; 7 | } 8 | 9 | const denominations = [10000, 5000, 1000, 500, 100, 50, 10]; 10 | const changeResult = {}; 11 | 12 | for (const denomination of denominations.reverse()) { 13 | const count = Math.min(Math.floor(change / denomination), 100); // 최대 100개씩 사용 가능 14 | 15 | if (count > 0) { 16 | changeResult[denomination] = count; 17 | change -= denomination * count; 18 | } 19 | } 20 | 21 | if (change === 0) { 22 | console.log("손님에게 최대한 많은 잔돈을 주는 방법:"); 23 | console.log(changeResult); 24 | } else { 25 | console.log("거스름돈을 줄 수 없습니다. (동전/지폐가 부족합니다.)"); 26 | } 27 | } 28 | 29 | giveChange(5000, 10000); 30 | -------------------------------------------------------------------------------- /5장/5-3.js: -------------------------------------------------------------------------------- 1 | function maxMeetings(meetings) { 2 | // 종료 시간으로 정렬 3 | meetings.sort((a, b) => a[1] - b[1]); 4 | 5 | let currentMeeting = meetings[0]; 6 | let count = 1; 7 | 8 | for (let i = 1; i < meetings.length; i++) { 9 | // 다음 미팅의 시작 시간이 현재 미팅의 종료 시간보다 늦거나 같으면 10 | // 예약하고 현재 미팅을 업데이트합니다 11 | if (meetings[i][0] >= currentMeeting[1]) { 12 | currentMeeting = meetings[i]; 13 | count++; 14 | } 15 | } 16 | 17 | return count; 18 | } 19 | 20 | let meetings = [ 21 | [0, 2], 22 | [1, 3], 23 | [2, 4], 24 | [3, 5], 25 | [4, 6], 26 | ]; 27 | console.log(maxMeetings(meetings)); // 결과: 3 28 | -------------------------------------------------------------------------------- /5장/5-4.js: -------------------------------------------------------------------------------- 1 | const meetings = [ 2 | [0, 2], 3 | [1, 3], 4 | [2, 4], 5 | [3, 5], 6 | [4, 6], 7 | ]; 8 | 9 | function minMeetings(meetings) { 10 | // 회의를 종료 시간 기준으로 정렬 11 | meetings.sort((a, b) => a[1] - b[1]); 12 | 13 | let lastEndTime = -1; 14 | let count = 0; 15 | 16 | for (const meeting of meetings) { 17 | if (meeting[0] >= lastEndTime) { 18 | lastEndTime = meeting[1]; 19 | count++; 20 | } 21 | } 22 | 23 | // 전체 회의 수에서 겹치지 않는 회의 수를 뺀 값이 최소 회의 수 24 | return meetings.length - count; 25 | } 26 | 27 | const result = minMeetings(meetings); 28 | 29 | console.log(`가장 적게 참석해야 하는 최소 회의 수: ${result}`); // 예상 결과: 2 30 | -------------------------------------------------------------------------------- /5장/5-5.js: -------------------------------------------------------------------------------- 1 | function maxSeries(series, timeLimit) { 2 | // 총 시간별로 시리즈 정렬 3 | series.sort((a, b) => a.time - b.time); 4 | 5 | let count = 0; 6 | let currentTime = 0; 7 | 8 | for (let i = 0; i < series.length; i++) { 9 | // 남은 시간 동안 볼 수 있는 경우 10 | if (currentTime + series[i].time <= timeLimit) { 11 | currentTime += series[i].time; 12 | count++; 13 | } else { 14 | break; 15 | } 16 | } 17 | 18 | return count; 19 | } 20 | 21 | let series = [ 22 | { name: "더글로리 시즌2", time: 7.25 }, 23 | { name: "킹덤 시즌2", time: 4.5 }, 24 | { name: "스위트홈 2", time: 9.5 }, 25 | { name: "이태원클라쓰", time: 18.6 }, 26 | ]; 27 | let timeLimit = 20; 28 | 29 | console.log(maxSeries(series, timeLimit)); 30 | -------------------------------------------------------------------------------- /5장/5-6.js: -------------------------------------------------------------------------------- 1 | function maxValues(items, weightLimit) { 2 | items.sort((a, b) => b.value / b.weight - a.value / a.weight); 3 | 4 | let totalValue = 0; 5 | let currentWeight = 0; 6 | 7 | for (let item of items) { 8 | if (currentWeight + item.weight <= weightLimit) { 9 | currentWeight += item.weight; 10 | totalValue += item.value; 11 | } else { 12 | let remainingWeight = weightLimit - currentWeight; 13 | totalValue += item.value * (remainingWeight / item.weight); 14 | break; 15 | } 16 | } 17 | 18 | return totalValue; 19 | } 20 | 21 | let items = [ 22 | { name: "책", weight: 1, value: 6000 }, 23 | { name: "노트북", weight: 3, value: 20000 }, 24 | { name: "카메라", weight: 2, value: 15000 }, 25 | { name: "옷", weight: 2, value: 8000 }, 26 | ]; 27 | let weightLimit = 5; 28 | 29 | console.log(maxValues(items, weightLimit)); // 결과: 35000 30 | -------------------------------------------------------------------------------- /5장/5-7.js: -------------------------------------------------------------------------------- 1 | let S = "abcd"; 2 | let left = 0; 3 | let right = S.length - 1; 4 | let moveCount = 0; 5 | 6 | while (left < right) { 7 | if (S[left] === S[right]) { 8 | left++; 9 | right--; 10 | } else if (S[left] < S[right]) { 11 | right--; 12 | moveCount += 1; 13 | } else { 14 | left++; 15 | moveCount += 1; 16 | } 17 | } 18 | 19 | console.log(moveCount); // 출력: 3 20 | -------------------------------------------------------------------------------- /5장/5-8.js: -------------------------------------------------------------------------------- 1 | function makePalindrome(S) { 2 | let charCount = {}; 3 | for (let char of S) { 4 | if (char in charCount) { 5 | charCount[char]++; 6 | } else { 7 | charCount[char] = 1; 8 | } 9 | } 10 | 11 | let oddCount = 0; 12 | let oddChar = ""; 13 | let evenChars = []; 14 | 15 | for (let char in charCount) { 16 | if (charCount[char] % 2 === 0) { 17 | for (let i = 0; i < charCount[char] / 2; i++) { 18 | evenChars.push(char); 19 | } 20 | } else { 21 | oddCount++; 22 | oddChar = char; 23 | if (oddCount > 1) { 24 | return false; 25 | } 26 | for (let i = 0; i < Math.floor(charCount[char] / 2); i++) { 27 | evenChars.push(char); 28 | } 29 | } 30 | } 31 | 32 | let palindrome = evenChars.join("") + oddChar + evenChars.reverse().join(""); 33 | return palindrome; 34 | } 35 | 36 | console.log(makePalindrome("ABDAB")); // 출력: 'ABDBA' 37 | console.log(makePalindrome("ABDAB23")); // 출력: false 38 | -------------------------------------------------------------------------------- /6장/6-1.js: -------------------------------------------------------------------------------- 1 | function solveNQueens(n) { 2 | let board = Array(n) 3 | .fill() 4 | .map(() => Array(n).fill(false)); 5 | let solutions = []; 6 | 7 | function isValid(row, col) { 8 | for (let i = 0; i < row; i++) { 9 | if (board[i][col]) { 10 | return false; 11 | } 12 | } 13 | 14 | for (let i = row, j = col; i >= 0 && j >= 0; i--, j--) { 15 | if (board[i][j]) { 16 | return false; 17 | } 18 | } 19 | 20 | for (let i = row, j = col; i >= 0 && j < n; i--, j++) { 21 | if (board[i][j]) { 22 | return false; 23 | } 24 | } 25 | 26 | return true; 27 | } 28 | 29 | function placeQueen(row) { 30 | if (row === n) { 31 | solutions.push( 32 | board.map((row) => row.map((col) => (col ? "Q" : ".")).join("")) 33 | ); 34 | return; 35 | } 36 | 37 | for (let col = 0; col < n; col++) { 38 | if (isValid(row, col)) { 39 | board[row][col] = true; 40 | placeQueen(row + 1); 41 | board[row][col] = false; 42 | } 43 | } 44 | } 45 | 46 | placeQueen(0); 47 | return solutions; 48 | } 49 | 50 | console.log(solveNQueens(4)); 51 | -------------------------------------------------------------------------------- /6장/6-2.js: -------------------------------------------------------------------------------- 1 | function solveNKnight(n) { 2 | let board = Array(n) 3 | .fill() 4 | .map(() => Array(n).fill(false)); 5 | let solutions = []; 6 | 7 | let dx = [-2, -1, 1, 2, -2, -1, 1, 2]; 8 | let dy = [1, 2, 2, 1, -1, -2, -2, -1]; 9 | 10 | function isAttack(i, j) { 11 | for (let k = 0; k < 8; k++) { 12 | let x = i + dx[k]; 13 | let y = j + dy[k]; 14 | if (x >= 0 && y >= 0 && x < n && y < n && board[x][y]) { 15 | return true; 16 | } 17 | } 18 | return false; 19 | } 20 | 21 | function solve(row) { 22 | if (row === n) { 23 | solutions.push( 24 | board.map((row) => row.map((col) => (col ? "K" : ".")).join("")) 25 | ); 26 | return; 27 | } 28 | 29 | for (let col = 0; col < n; col++) { 30 | if (!isAttack(row, col)) { 31 | board[row][col] = true; 32 | if (solve(row + 1)) { 33 | return true; 34 | } 35 | board[row][col] = false; 36 | } 37 | } 38 | return false; 39 | } 40 | 41 | solve(0); 42 | return solutions; 43 | } 44 | 45 | console.log(solveNKnight(4)); 46 | -------------------------------------------------------------------------------- /6장/6-3.js: -------------------------------------------------------------------------------- 1 | let N = 8; 2 | 3 | let sol = [ 4 | [-1, -1, -1, -1, -1, -1, -1, -1], 5 | [-1, -1, -1, -1, -1, -1, -1, -1], 6 | [-1, -1, -1, -1, -1, -1, -1, -1], 7 | [-1, -1, -1, -1, -1, -1, -1, -1], 8 | [-1, -1, -1, -1, -1, -1, -1, -1], 9 | [-1, -1, -1, -1, -1, -1, -1, -1], 10 | [-1, -1, -1, -1, -1, -1, -1, -1], 11 | [-1, -1, -1, -1, -1, -1, -1, -1], 12 | ]; 13 | 14 | let moveX = [2, 1, -1, -2, -2, -1, 1, 2]; 15 | let moveY = [1, 2, 2, 1, -1, -2, -2, -1]; 16 | -------------------------------------------------------------------------------- /6장/6-4.js: -------------------------------------------------------------------------------- 1 | let N = 8; 2 | 3 | let sol = [ 4 | [-1, -1, -1, -1, -1, -1, -1, -1], 5 | [-1, -1, -1, -1, -1, -1, -1, -1], 6 | [-1, -1, -1, -1, -1, -1, -1, -1], 7 | [-1, -1, -1, -1, -1, -1, -1, -1], 8 | [-1, -1, -1, -1, -1, -1, -1, -1], 9 | [-1, -1, -1, -1, -1, -1, -1, -1], 10 | [-1, -1, -1, -1, -1, -1, -1, -1], 11 | [-1, -1, -1, -1, -1, -1, -1, -1], 12 | ]; 13 | 14 | let moveX = [2, 1, -1, -2, -2, -1, 1, 2]; 15 | let moveY = [1, 2, 2, 1, -1, -2, -2, -1]; 16 | 17 | function isSafe(x, y, sol) { 18 | return x >= 0 && x < N && y >= 0 && y < N && sol[x][y] == -1; 19 | } 20 | 21 | function printSolution(sol) { 22 | for (let x = 0; x < N; x++) { 23 | for (let y = 0; y < N; y++) { 24 | console.log(sol[x][y] + " "); 25 | } 26 | console.log("\n"); 27 | } 28 | } 29 | 30 | function solveKT() { 31 | sol[0][0] = 0; 32 | if (!solveKTUtil(0, 0, 1, sol, moveX, moveY)) { 33 | console.log("Solution does not exist"); 34 | return false; 35 | } else { 36 | printSolution(sol); 37 | } 38 | return true; 39 | } 40 | 41 | function solveKTUtil(x, y, moveI, sol, moveX, moveY) { 42 | let k, nextX, nextY; 43 | if (moveI == N * N) return true; 44 | for (k = 0; k < 8; k++) { 45 | nextX = x + moveX[k]; 46 | nextY = y + moveY[k]; 47 | if (isSafe(nextX, nextY, sol)) { 48 | sol[nextX][nextY] = moveI; 49 | if (solveKTUtil(nextX, nextY, moveI + 1, sol, moveX, moveY)) return true; 50 | else sol[nextX][nextY] = -1; // 백트레킹 51 | } 52 | } 53 | return false; 54 | } 55 | 56 | solveKT(); 57 | -------------------------------------------------------------------------------- /6장/6-5.js: -------------------------------------------------------------------------------- 1 | function permute(arr) { 2 | if (arr.length === 1) { 3 | return [arr]; 4 | } 5 | 6 | let permutations = []; 7 | for (let i = 0; i < arr.length; i++) { 8 | let rest = arr.slice(0, i).concat(arr.slice(i + 1)); 9 | for (let subPermutation of permute(rest)) { 10 | permutations.push([arr[i]].concat(subPermutation)); 11 | } 12 | } 13 | 14 | return permutations; 15 | } 16 | 17 | function tsp(distances) { 18 | let cities = Object.keys(distances); 19 | let shortestDistance = Infinity; 20 | let shortestPath; 21 | 22 | for (let permutation of permute(cities)) { 23 | let distance = 0; 24 | for (let i = 0; i < permutation.length - 1; i++) { 25 | distance += distances[permutation[i]][permutation[i + 1]]; 26 | } 27 | distance += distances[permutation[permutation.length - 1]][permutation[0]]; 28 | 29 | if (distance < shortestDistance) { 30 | shortestDistance = distance; 31 | shortestPath = permutation; 32 | } 33 | } 34 | 35 | return { shortestDistance, shortestPath }; 36 | } 37 | 38 | let distances = { 39 | A: { A: 0, B: 1, C: 3, D: 4 }, 40 | B: { A: 1, B: 0, C: 2, D: 5 }, 41 | C: { A: 3, B: 2, C: 0, D: 6 }, 42 | D: { A: 4, B: 5, C: 6, D: 0 }, 43 | }; 44 | 45 | console.log(tsp(distances)); 46 | -------------------------------------------------------------------------------- /6장/6-6.js: -------------------------------------------------------------------------------- 1 | const N = 5; 2 | const M = 21; 3 | const cards = [5, 6, 7, 8, 9]; 4 | let answer = 0; 5 | 6 | for (let i = 0; i < N; i++) { 7 | for (let j = i + 1; j < N; j++) { 8 | for (let k = j + 1; k < N; k++) { 9 | let sum = cards[i] + cards[j] + cards[k]; 10 | if (sum <= M) { 11 | answer = Math.max(answer, sum); 12 | } 13 | } 14 | } 15 | } 16 | 17 | console.log(answer); 18 | -------------------------------------------------------------------------------- /7장/7-1.js: -------------------------------------------------------------------------------- 1 | let arr = []; 2 | 3 | for (let i = 0; i < 1000000; i++) { 4 | arr.push(new Array(100)); 5 | } 6 | -------------------------------------------------------------------------------- /7장/7-2.js: -------------------------------------------------------------------------------- 1 | let arr = []; 2 | 3 | for (let i = 0; i < 1000000; i++) { 4 | let subArr = new Array(100); 5 | // subArr를 사용하는 코드 6 | // ... 7 | subArr = null; // 더 이상 필요하지 않은 메모리 해제 8 | } 9 | -------------------------------------------------------------------------------- /7장/7-3.js: -------------------------------------------------------------------------------- 1 | let btn = document.getElementById("myButton"); 2 | btn.addEventListener("click", function () { 3 | // 클릭 발생 때 실행할 코드 4 | }); 5 | 6 | // 후에 필요 없어진 경우 7 | btn.removeEventListener("click", function () { 8 | // 이벤트 제거 후 실행될 코드 9 | }); 10 | -------------------------------------------------------------------------------- /7장/7-4.js: -------------------------------------------------------------------------------- 1 | let timerId = setInterval(() => { 2 | // 타이머 설정 3 | }, 1000); 4 | 5 | // 후에 필요 없어진 경우 6 | clearInterval(timerId); 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 쉽게 설명한 자바스크립트 알고리즘 - 저자 한상훈 2 | 3 | 이 레포지토리는 '쉽게 설명한 자바스크립트 알고리즘(출판사: 영진닷컴)'에 예제 소스코드를 담고 있는 레포지토리입니다. 4 | 5 | ## 예제 소스코드 실행 방법 6 | 7 | ### Node.js 설치 8 | 9 | [Node.js 홈페이지](https://nodejs.org/en)에 방문해 설치 가이드를 따라 설치합니다. 10 | 11 | ### 예제 소스코드 실행 12 | 13 | 1. 터미널에서 레포지토리를 클론합니다. 14 | 2. 이 프로젝트는 별도의 모듈 설치가 필요하지 않습니다. 15 | 3. 터미널에서 예제 소스코드를 실행하려는 파일의 경로로 이동합니다. 16 | 4. 터미널에서 `node 파일명.js` 명령어를 실행하여 예제 소스코드를 실행합니다. 17 | 18 | ### IDE 설치 19 | 20 | [VSCode 홈페이지](https://code.visualstudio.com/)에 방문해 설치 가이드를 따라 설치합니다. 21 | 또는 [Cursor 홈페이지](https://cursor.com/)에 방문해 설치 가이드를 따라 설치합니다. 22 | --------------------------------------------------------------------------------