diff --git "a/parkHyeJung/Section04/02-\353\222\244\354\247\221\354\235\200\354\206\214\354\210\230.js" "b/parkHyeJung/Section04/02-\353\222\244\354\247\221\354\235\200\354\206\214\354\210\230.js" new file mode 100644 index 0000000..0ba19d5 --- /dev/null +++ "b/parkHyeJung/Section04/02-\353\222\244\354\247\221\354\235\200\354\206\214\354\210\230.js" @@ -0,0 +1,85 @@ +/* +[문제] +N개의 자연수가 입력되면 각 자연수를 뒤집은 후 소수이면 그 소수를 출력하는 프로그램을 작성하세요. + +예시) +* 32를 뒤집으면 23, 23은 소수. => 23 출력 +* 910 뒤집으면 19 => 첫 자리부터 연속된 0 무시 +*/ + +// 소수판별 알고리즘 +const isPrime = num => { + // 인자로 들어온 num === filteredArr에서 전달되는 각 배열의 숫자 n + // 1 이하일 경우 소수가 아니므로 false + if (num <= 1) return false; + + // 제곱근까지 비교하여 나누어떨어지는 수가 있는지 확인 + // 12 => 1*12 / 2*6 / 3*4 / 4*3/ 6*2 ... => 4까지 확인하면 나머지 숫자는 같은 숫자의 반복이므로 상관없다. + for (let i = 2; i <= parseInt(Math.sqrt(num)); i++) { + if (num % i === 0) return false; + } + return true; +}; + +// 필터링 알고리즘 +const reversePrime = arr => { + // map => 뒤집은 숫자 배열 + // filter => isPrime에 해당하는 숫자만 모음 + const filteredArr = arr + .map(num => { + return Number(String(num).split('').reverse().join('')); + }) + .filter(num => isPrime(num)); + + // filteredArr을 순회하며 출력 + filteredArr.forEach(num => console.log(num)); +}; + +const arr = [32, 55, 62, 20, 250, 370, 200, 30, 100]; +const N = arr.lenght; +// let result1 = reversePrime(arr); + +/* +[풀이 과정] + +* 시도 1 +- 각 자연수를 뒤집은 숫자를 만든다. +... 뒤집을 때 메서드를 사용했는데 다른 방법은 없는가..?? +- 각 수가 소수인지 판별 : 소수 판별 알고리즘을 만든다. +- 소수 판별 알고리즘? 2 ~ 각 수의 제곱근까지와 비교해 나뉘어 떨어지는것이 있는지 판별. + +*/ + +function answer(arr) { + let answer = []; + for (let x of arr) { + // 뒤집어지는 수가 저장되는 res + let res = 0; + while (x) { + let t = x % 10; + res = res * 10 + t; + x = parseInt(x / 10); + } + if (isPrime(res)) answer.push(res); + } + return answer; +} +let result2 = answer(arr); +console.log(result2); + +/* +[답안 해설] +- arr의 숫자들을 x 로 반복하면서, x의 각 자릿수를 뜯어서 자리를 바꾸는 방법이다. +- x === 32 일 때. + +* 1번째 반복 : x === 32 +... t = x % 10 => 32를 10으로 나눈 나머지이므로 t === 2가 된다. +... res = res * 10 + t => 0 * 10 + 2 이므로 res === 2가 된다. +... x = parseInt(x / 10) => 32를 10으로 나눈 몫이므로 3이 된다. + +* 2번째 반복 : x === 3 +... t = x % 10 => 3을 10으로 나눈 나머지이므로 t === 3이 된다. +... res = res * 10 + t => 2 * 10 + 3 이므로 23이 된다. (***) +... x = parseInt(x / 10) => parseInt( 3 / 10 ) === 0 이기 때문에 while문이 종료된다. + +*/ diff --git "a/parkHyeJung/Section04/05-K\353\262\210\354\247\270\355\201\260\354\210\230.js" "b/parkHyeJung/Section04/05-K\353\262\210\354\247\270\355\201\260\354\210\230.js" new file mode 100644 index 0000000..184cdec --- /dev/null +++ "b/parkHyeJung/Section04/05-K\353\262\210\354\247\270\355\201\260\354\210\230.js" @@ -0,0 +1,90 @@ +/* +[문제] +현수는 1부터 100사이의 자연수가 적힌 N장의 카드를 가지고 있습니다. 같은 숫자의 카드가 +여러장 있을 수 있습니다. 현수는 이 중 3장을 뽑아 각 카드에 적힌 수를 합한 값을 기록하려 +고 합니다. 3장을 뽑을 수 있는 모든 경우를 기록합니다. 기록한 값 중 K번째로 큰 수를 출력 +하는 프로그램을 작성하세요. +만약 큰 수부터 만들어진 수가 25 25 23 23 22 20 19......이고 K값이 3이라면 K번째 큰 값 +은 22입니다. + +[출력] +K번째 수가 존재하지 않으면 -1을 출력한다. + +*/ + +function kLargestNum(N, K, cards) { + // cards 배열 내림차순 정렬 + cards.sort((a, b) => b - a); + + // 3개를 뽑은 합계를 담을 배열 sums + let sums = []; + + // 숫자를 3회 뽑아야 하므로, for문을 3번 돈다. 중복 방지를 위해서 각각 0, 1, 2 순서로 진행. + for (let i = 0; i < N; i++) { + for (let j = i + 1; j < N; j++) { + for (let k = j + 1; k < N; k++) { + // 3번째 for문에서 각 순서대로 뽑힌 카드를 더한 값을 배열에 담아준다. + sums.push(cards[i] + cards[j] + cards[k]); + } + } + } + // 3번째로 '큰' 값, 즉 중복을 제외한 값이어야 하기 때문에 set을 사용해 중복제거 후 다시 배열로 변환 + sums = [...new Set(sums)]; + + // 해당 배열에 K번째 큰 수가 존재하면 리턴하고 아닐 경우 -1을 리턴 + return sums[K - 1] ? sums[K - 1] : -1; +} + +const N = 10; // cards.length +const K = 3; +const cards = [13, 15, 34, 23, 45, 65, 33, 11, 26, 42]; + +const result1 = kLargestNum(N, K, cards); +// console.log(result1); + +/* +[풀이과정] + +* 시도1 +- 3중 for문... 을 사용해서 각 숫자 조합을 만들고 배열에 입력한다. +... 숫자를 내림차순으로 정렬하면 k번째 숫자가 더 빨리 나오지 않을까? +... 배열의 길이가 k를 넘어가는 순간 반복문을 중지하고 리턴. +=> 중복된 값이 있다는 것을 미처 생각하지 못했다! 다시 수정했음 + +* 시도2 +- 3중 for문으로 모든 경우를 배열에 담은 뒤 Set으로 중복을 제거하고 해당하는 인덱스로 접근하여 리턴. +*/ + +function answer(N, K, cards) { + // 3개를 뽑은 합이 중복되지 않고 추가되도록 Set을 생성한다. + let sums = new Set(); + + // 반복을 3중으로 돌아서 중복되지 않는 모든 경우의 조합을 만든다. + for (let i = 0; i < N; i++) { + for (let j = i + 1; j < N; j++) { + for (let k = j + 1; k < N; k++) { + // Set 에 add 메서드를 사용해 합계를 추가할 수 있다. + sums.add(cards[i] + cards[j] + cards[k]); + console.log(i, j, k); + } + } + } + + // K번째 큰 수를 출력하는 것이므로 sums를 배열로 변환하고 내림차순 정렬한 후 출력한다. + sums = [...sums].sort((a, b) => b - a); + return sums[K - 1] ? sums[K - 1] : -1; +} +const result2 = answer(N, K, cards); +console.log(result2); + +/* +[Set 자료구조 정리] +- '중복되지 않는 유일한 값들의 집합'이다. set 안에 존재하는 한 값은 유일한 값이다. +- 이터러블한 자료구조로 반복할 수 있지만, 순서에 의미가 없고 그렇기 때문에 index 개념도 없다. +- set.size : 요소의 갯수를 확인 +- set.add(el) : 요소 추가 +- set.has(el) : el 이 set에 존재하는지 여부를 확인할 수 있다.(boolean 값 리턴) +- set.delete(el) : el이 set에 존재할 경우 삭제하고, 삭제 여부에 대한 boolean 값을 리턴한다. +- set.clear() : 전체 요소를 삭제할 수 있고, undefined를 반환한다. +- for...of나 forEach 메서드로 순회할 수 있다. forEach를 사용했을 때 두 번째 인자는 index 대신 해당 요소임. +*/ diff --git "a/parkHyeJung/Section04/Section04_\354\231\204\354\240\204\355\203\220\354\203\211.md" "b/parkHyeJung/Section04/Section04_\354\231\204\354\240\204\355\203\220\354\203\211.md" new file mode 100644 index 0000000..d2c1e3f --- /dev/null +++ "b/parkHyeJung/Section04/Section04_\354\231\204\354\240\204\355\203\220\354\203\211.md" @@ -0,0 +1,29 @@ +# Section_04 완전탐색 + +## 개요 + +- 모든 경우를 탐색해보는 알고리즘(방법), 가능한 경우의 수를 일일이 나열하면서 해당되는 답을 찾는 방법이다. +- 가능한 모든 경우를 (무식하게) 나열하며 찾기 때문에, 100% 정답을 도출할 수는 있지만 그 속도가 굉장히 느린 편이다. +- 문제를 해결할 수는 있지만 그 효율성이 떨어지기 때문에 너무 많은 경우의 수를 도출해야 하는 경우 적절하지 않은 방법이다. +- 완전탐색이 어떤 특정한 알고리즘 기법이라기 보다는, 그냥 모든 경우의 수를 다 구하며 문제를 해결하는 방식이면 완전탐색이라고 할 수 있다. + +## 적용 방법 + +1. 해결하고자 하는 문제의 경우의 수를 대략적으로 계산한다. +2. 가능한 모든 방법을 다 고려한다. +3. 실제 답을 구할 수 있는지 적용해본다. + +이 문제가 완전탐색을 적용하기에 알맞은 문제인지 파악한 뒤에, +완전 탐색 중에서도 구체적으로 어떤 방식을 사용할 것인지 고려하여 적용한다. + +## 해당하는 알고리즘 종류 + +1. **Brute Force 기법** : 반복문 / 조건문을 활용해 가능한 모든 경우를 나열하는 방법 +2. **순열** : n개의 원소 중 r 개만큼의 원소를 중복 없이 나열하는 방법 (순서가 중요하다.) +3. **재귀 호출** : 재귀 식을 가지고 자기 자신을 반복 호출하는 알고리즘, 반복문으로 코드를 작성할 때 반복문의 중첩 횟수를 예측할 수 없거나 중첩이 과다하게 많은 경우 적용해볼 수 있다. +4. **비트마스크** : 2진수 표현을 활용해 집합과 부분집합을 구할 수 있는 알고리즘. 2진수의 자릿수를 활용해 즉 0과 1인 bit 를 가지고 빠르게 연산한다는 장점이 있음. +5. **DFS, BFS** : 그래프 자료구조에서 '모든 정점을 탐색'하기 위한 방법. + +### 참고자료 + +[알고리즘-완전탐색(Exhaustive Search)](https://hongjw1938.tistory.com/78)