Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions parkHyeJung/Section04/02-뒤집은소수.js
Original file line number Diff line number Diff line change
@@ -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문이 종료된다.

*/
90 changes: 90 additions & 0 deletions parkHyeJung/Section04/05-K번째큰수.js
Original file line number Diff line number Diff line change
@@ -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 대신 해당 요소임.
*/
29 changes: 29 additions & 0 deletions parkHyeJung/Section04/Section04_완전탐색.md
Original file line number Diff line number Diff line change
@@ -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)