programmers weekly challenge

12주 차까지 12문제 모두 풀었다!

  • 1주 차는 그냥 생각 없이 풀고 제출했는데, 다른 사람 풀이를 보니까 너무 쇼킹했다
  • 좋아요 한번 받아보려고 새로운 문제 오픈되자마자 빠르게도 풀어보고, 제출하기 전에 코드 최대한 압축해서 제출도 해보았다
  • 근데 좋아요 한 개도 못 받았다 ㅋㅋ ㅠㅠ
  • 나름 짧게 잘 푼 것 같아 제출해도 항상 더 쇼킹한 풀이를 보았다..
  • 어려운 문제가 나오면 포기할까 싶었는데, 나중에 스샷 찍었을 때 풀었다는 표식을 남기고 싶어서 끝까지 한 것 같다
  • 시간제한도 없고 편하게 할 수 있어서 재밌었다!

참고

124 나라 숫자

124 나라 숫자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// https://programmers.co.kr/learn/courses/30/lessons/12899
function solution12909(n) {
var answer = [];
var arr = '';
var N = n;

var seq = ['4', '1', '2'];
// console.log(seq[seq.length - 1]);
while (true) {
var tmp = n % 3;

answer.push(tmp);
// if (n <= 2) {
// break;
// }

if (tmp == 0) {
n = (n - tmp - 3) / 3;
} else {
n = (n - tmp) / 3;
}

if (n == 0) {
break;
}
}

while (answer.length != 0) {
arr += seq[answer.pop()];
}

// console.log(answer);
// console.log(N, arr);
// console.log("------------");
return arr;
}

해설

  • 124라는 나라의 이상한 진법으로 변환해야 하는 문제이다
  • 10진법 124 나라 10진법 124 나라
    1 1 6 14
    2 2 7 21
    3 4 8 22
    4 11 9 24
    5 12 10 41
  • 이렇게 이상한 숫자로 변환시키는 문제이다
  • 3진법 같아 보이지만 여기에는 함정이 있다….
  • 3진법이 아닌데 3개 숫자로만 표현해야한다
  • 경험으로 알게된.. 자릿수가 바뀔때 이상하게 바뀐다는 건데..
  • 나머지가 0이 될 경우에 == n이 3의 배수의 경우에 추가로 처리해줘야한다
  • 이해?를 돕기위해 그림을 그렸다
  • 왼쪽이 일반적인.. 상식적인 3진수이고
  • 오른쪽이 124 나라의 수이다
  • 중간은 124 나라의 수인데, 3진수와 시작을 똑같이 하기 위해 조작한 것이다
  • 3진수와 중간을 비교해보면 중간중간 정신나간 부분이 보인다
  • 이런 특징? 때문에 124나라는 적은 자릿수로 더 많은 숫자를 표현할 수 있다

  • 이문제는 해결법을 짠하고 알아냈다기보다
  • 계속 해보면서 알게된 규칙들을 적용시키면서 풀린거라
  • 설명을 잘 못하겠다..

  • 숫자 때문에 헷갈려 죽을뻔..
  • 아무튼 정신나간 124 나라이다

가장 큰 정사각형 찾기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// https://programmers.co.kr/learn/courses/30/lessons/12905
// 가장 큰 정사각형 찾기
function solution(board) {
var answer = 1;

var lownum = board.length;
var colnum = board[0].length;
console.log(lownum, colnum);

if (lownum == 1 || colnum == 1) {
var maxRow = board.map(function (row) {
return Math.max.apply(null, row);
});
var max = Math.max.apply(null, maxRow);

return max;
}

var max = 0;

for (var q = 1; q < board.length; q++) {
for (var w = 1; w < board[0].length; w++) {
if (board[q][w] == 0) {
continue;
}
var arr = [board[q - 1][w - 1], board[q - 1][w], board[q][w - 1]];
board[q][w] = Math.min.apply(null, arr) + 1;
max = Math.max(max, board[q][w]);
}
}

answer = max * max;

// console.log(maxRow, max);
console.log(answer);
return answer;
}

해설

  • 2차원 배열이 입력으로 들어온다

  • 2차월 연속된 1 이 이루는 가장 큰 정사각형의 넓이를 반환해야 한다

  • 먼저 입력된 보드가 행과 열 어느 하나가 1인 경우 1또는 0을 반환한다

  • 이제 1이 아닌 경우에 복잡해 지는데..

  • 0과 1로만 이루어진 보드를 갱신해 나갈거다

  • board[1][1] 부터 시작해서 이전 3개를 살펴볼것이다

  • 이때 board[1][1]이 0 이면 패스한다. 1이면 ㄱㄱ

  • 위, 왼쪽, 왼쪽 대각선위를 살펴서 가장 작은 숫자를 찾는다

  • 그런다음에 board[1][1]에 가장 작은 숫자 + 1을 대입한다

  • board[1][2] 로 이동해서 같은 것을 반복한다

  • 그림으로 보면 이렇다

  • step1] board[1][1] 일때

  • step1] board[1][2] 일때

  • 반복…

  • 결과]

  • 위 처럼 계속 갱신하고 보드에 마지막에 도달하면 끝이 난다

  • 이후에 board 내에서 가장 높은 숫자를 찾는다. 그러면 3이라는 숫자를 얻을 수 있다

  • 넓이를 반환하고 했으니까 3*3 해서 9를 반환하면 된다

완주하지 못한 선수

완주하지 못한 선수
1
2
3
4
5
6
7
8
9
10
11
12
13
// https://programmers.co.kr/learn/courses/30/lessons/42576
const solution = (participant, completion) => {
let objComletion = {};

completion.forEach((item) => {
!objComletion[item] ? (objComletion[item] = 1) : objComletion[item]++;
});

for (let i = 0; i < participant.length; i++)
if (!objComletion[participant[i]] || --objComletion[participant[i]] < 0)
return participant[i];
};
result = solution(['leo', 'kiki', 'eden'], ['eden', 'kiki']);
  • 효율성때문에 골치 아픈 문제

해설

  • solution(['leo', 'kiki', 'eden'], ['eden', 'kiki'])
  • 이런식으로 이름이 들어간 2개의 배열이 들어온다
  • 첫번째 배열은 참가자명단이고
  • 두번째 배열은 완주자명단이다
  • 완주하지 못한 사람을 반환하면 된다
  • 그런데 동명이인이 있을 수 있다
  • 중첩 반복문으로 풀다가 효율성에서 실패했다
  • 해쉬를 써서 풀라는데, 그러다 생각한데 객체를 만들어서 접근하는 방식이다..
  • objComletion라는 객체를 하나 생성하고
  • 반복분으로 objComletion.사람이름 으로 초기화한다
  • 초기화할때 멤버가 없으면 1로 초기화하고 이미 존재하면 ++해서 동명이인 처리를 했다
  • participant(참가자) 배열로 반목문을 돌면서 사람이름으로 다이렉트로 접근하니까 효율성이 엄청 좋아졌다
  • 멤버가 없거나, 0일경우 완주하지 못한 선수를 잡아낼 수 있다

잡담

  • 이 문제 풀면서 겉멋 코드에 맛들려서 안쓰던 화살표 함수도 쓰고…
  • 변수명 &, _ 이런거도 써봤다..ㅋㅋ
  • 효율성 획기적으로 줄여서 기분이 좋았다

모의고사

모의고사
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// https://programmers.co.kr/learn/courses/30/lessons/42840
function solution(answers) {
const a = [1, 2, 3, 4, 5];
const b = [2, 1, 2, 3, 2, 4, 2, 5];
const c = [3, 3, 1, 1, 2, 2, 4, 4, 5, 5];

let count = [0, 0, 0];
answers.forEach((element, index) => {
a[index % a.length] == element ? count[0]++ : null;
b[index % b.length] == element ? count[1]++ : null;
c[index % c.length] == element ? count[2]++ : null;
});
let result = [];
let max = Math.max.apply(null, count);
count.forEach((item, idx) => {
if (max == item) {
result.push(idx + 1);
}
});
return result;
}
solution([1, 2, 3, 4, 5]);

해설

  • 입력으로 정답 배열이 들어온다
  • a,b,c 세 사람이 있다
  • 사람마다 찍기 타입이 있다
  • 각자 자신만의 패턴으로 문제를 찍었을때 가장 문제를 많이 맞힌 사람을 반환한다
  • 일단 찍기타입을 정의하고,
  • 각 사람마다 정답이면 카운트를 늘린다!
  • 나머지 연산으로 패턴을 지속한다. c[index % c.length]
  • 그 중에서 가장 많이 맞춘 사람 배열을 반환한다. (1~다수)

체육복

체육복
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// https://programmers.co.kr/learn/courses/30/lessons/42862
function solution(n, lost, reserve) {
var answer = 0;

let arr = [];
for (let i = 0; i < n; i++) {
arr[i] = 1;
}

for (let i = 0; i < reserve.length; i++) {
arr[reserve[i] - 1]++;
}

for (let i = 0; i < lost.length; i++) {
arr[lost[i] - 1]--;
}

for (let i = 0; i < arr.length; i++) {
// 앞에사람꺼 빌리기
if (arr[i] == 0) {
if (arr[i - 1] == 2) {
arr[i - 1]--;
arr[i]++;
continue;
}
// 뒤에사람꺼 빌리기
else if (arr[i + 1] == 2) {
arr[i + 1]--;
arr[i]++;
continue;
}
}
}

const result = arr.filter((value, index) => {
return value != 0;
});

return result.length;
}
solution(5, [2, 4], [1, 3, 5]);

해설

  • 체육복을 입을 수 있는 사람의 수를 구하는 문제다
  • 체육복을 빌릴 수 있는데, 앞 뒤 사람의 체육복만 빌릴 수 있다
  • 먼저 arr 배열을 초기화한다. lost는 -1, reserve는 +1
  • 앞에서부터 순차적으로 앞사람확인하고 여벌이 있으면 빌린다
  • 앞사람없으면 뒤에서 빌린다

2016년

2016년
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// https://programmers.co.kr/learn/courses/30/lessons/12901
// 1월:31일
// 2월:29일
// 3월:31일
// 4월:30일
// 5월:31일
// 6월:30일
// 7월:31일
// 8월:31일
// 9월:30일
// 10월:31일
// 11월:30일
// 12월:31일
function solution(a, b) {
const days = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
const dow = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'];
let eachFirstDow = [5];
let tmp;
// setup process
for (let i = 1; i < a; i++) {
tmp = days[i - 1] % 7;
console.log(i + 1, dow[(eachFirstDow[i - 1] + tmp) % 7]);
eachFirstDow[i] = (eachFirstDow[i - 1] + tmp) % 7;
}
eachFirstDow.forEach((item) => {
console.log(dow[item]);
});
tmp = (b - 1) % 7;
return dow[(eachFirstDow[a - 1] + tmp) % 7];
}
result = solution(10, 1);
result = solution(5, 24);

해설

  • 2016년은 윤년이다
  • a월 b일을 입력받았을때 무슨요일인지 반환하는 문제이다
  • 나는 dow에 요일을 넣었다
  • 1월 1일은 무슨 요일인지 확인한다
  • 확인 결과 금요일이다
  • 첫번째 반복문에서 각 월 1일의 요일을 구한다
  • a월 1일의 요일에서 (b-1)일을 더하고 7로 나누면 해당일의 요일을 구할 수 있다

소수 찾기

소수 찾기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// https://programmers.co.kr/learn/courses/30/lessons/12921
function solution(n) {
var answer = 0;
let sosu = [];
let arr = {};
for (let i = 2; i <= n; i++) {
arr[i] = 1;
}

for (let index = 2; index <= n; index++) {
const element = arr[index];
if (element == 0) {
console.log('index', index);
continue;
}
sosu.push(index);
let a = 2;
// 지금 현재 값을
while (true) {
if (!(arr[index * a] + 1)) {
break;
}
arr[index * a++] = 0;
console.log(index * a);
}
}
console.log('소수:', sosu);
return sosu.length;
}
result = solution(10);
  • 효율성 통과하기 어려웠다

해설

  • 정수 n을 입력받으면 1부터 n 사이의 소수의 개수를 반환한다
  • 효율성을 통과할려면 에라토스테네스의 체를 써야한다
  • 에라토스테네스의 체 알고리즘을 구현한다
  • 글로 적힌거 봣는데 하나도 이해가 안되서, 위 그림을 보고 구현했다. (역시 그림이 최고!)
  • 첫번째 반복문에서 2부터 n까지 1로 초기화한다
  • 이제 2부터 n까지 반복문을 돈다
  • 처음에 2는 소수다. 소수 배열에 추가하고 while루프에서 arr배열에서 2의 2배수를 전부 지운다
  • 여기서 지운다는 것은 arr[2의배수] = 0 으로 만드는 것!
  • 그러면 다음 루프 3… 똑같이한다
  • 그다음 4에서 arr[4] == 0 이기때문에 바로 패스한다
  • … 반복
  • 내 글로된 설명보다 그림보는게 훨씬 이해에 빠를것이다!

에라토스테네스의 체

  • 소수를 찾는 방법

약수의 합

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// https://programmers.co.kr/learn/courses/30/lessons/12928
function solution(n) {
if (n == 0 || n == 1) {
return n;

let arr = [1, n];
console.log(Math.sqrt(n));
for (let index = 2; index <= Math.sqrt(n); index++) {
if (n % index == 0) {
arr.push(index);
if (index == Math.sqrt(n)) {
} else {
arr.push(n / index);
}
}
}
console.log(arr);
return arr.reduce((prev, curr) => {
console.log(prev, curr);
return curr + prev;
}, 0);
}
result = solution(12); //28

해설

  • 정수를 입력받으면 모든 약수의 합을 반환한다
  • 0, 1인 경우 바로 반환한다
  • 무조건 약수인 1과 자기자신으로 약수가 저장될 배열을 초기화한다
  • 2부터 n의 제곱근까지 반복문을 돌면서 나누어 떨어지는지 판단한다
  • 나누어 떨어지면 약수 배열에 추가한다
  • 약수는 항상 세트로 존재하기 때문에, 제곱근의 경우가 아니라면 n / index 도 약수로 추가한다
  • reduce로 약수배열의 합을 구한다

자릿수 더하기

자릿수 더하기
1
2
3
4
5
6
7
8
9
10
11
// https://programmers.co.kr/learn/courses/30/lessons/12931
function solution(n) {
let answer;
n = `${n}`;
n = n.split('');
answer = n.reduce((prev, curr) => {
return parseInt(curr) + parseInt(prev);
}, 0);
return answer;
}
result = solution(123);

해설

  • 각 자릿수를 더해서 반환한다
  • reduce로 각 자릿수의 합을 구한다