728x90

문제


https://programmers.co.kr/learn/courses/30/lessons/92334

 

코딩테스트 연습 - 신고 결과 받기

문제 설명 신입사원 무지는 게시판 불량 이용자를 신고하고 처리 결과를 메일로 발송하는 시스템을 개발하려 합니다. 무지가 개발하려는 시스템은 다음과 같습니다. 각 유저는 한 번에 한 명의

programmers.co.kr

 

코드


function solution(id_list, report, k) {
let answer = new Array(id_list.length).fill(0); //정답을 담을 배열 (배열의 길이는 유저 수와 같아야 하므로 배열 크기를 id_list.length로 설정)
let report_obj = {}; // key : 각 유저, value : key 유저를 신고한 유저의 id 를 배열로 담는 객체 생성
//객체의 key를 각 유저로 저장
id_list.map((user) => {
report_obj[user] = [];
});
//각 신고 결과에 대해
report.map((user) => {
let [from, to] = user.split(" "); //[신고한 유저, 신고당한 유저] 순서로 배열에 저장
//중복되는 신고는 제외하고 객체에 {신고당한유저 : [신고한 사람1, 신고한 사람2]} << 이런식으로 담기
if (!report_obj[to].includes(from)) {
report_obj[to].push(from);
}
});
//객체의 각 key에 대해 (신고당한 각 유저에 대해)
for (let key in report_obj) {
//key의 value 개수가 k개 이상이면 (신고한 사람이 k명 이상이면)
if (report_obj[key].length >= k) {
report_obj[key].map((user) => {
answer[id_list.indexOf(user)] += 1; //유저 배열에서 해당 key의 value에 있는 유저들(신고한 유저들)의 index를 찾아 answer배열에 해당 index 위치에 +1 하기
});
}
}
return answer;
}

 

후기


  • 나는 배열과 객체를 적절히 사용하여 풀이를 하였는데 다른 분의 풀이를 보니 Map 객체를 사용하면 코드가 좀 더 깔끔하게 나왔을 것 같다. level1 문제인데 역시 카카오다. 나한텐 너무 복잡하게 느껴져서 몇일만에 풀었다.ㅜㅜ 객체에 대한 지식이 부족한 탓으로 알고 이 기회에 객체에 대한 이해도를 더 높일 수 있는 계기가 되었다 
잘못된 내용이나 수정이 필요한 내용이 있으면 언제든 댓글 달아주세요 감사합니다 😀
728x90

문제


https://programmers.co.kr/learn/courses/30/lessons/42839

 

코딩테스트 연습 - 소수 찾기

한자리 숫자가 적힌 종이 조각이 흩어져있습니다. 흩어진 종이 조각을 붙여 소수를 몇 개 만들 수 있는지 알아내려 합니다. 각 종이 조각에 적힌 숫자가 적힌 문자열 numbers가 주어졌을 때, 종이

programmers.co.kr

 

코드


function solution(numbers) {
const arr = numbers.split("");
const answer = new Set(); //정답(소수)을 넣을 set 선언
getPermutation(arr, ""); //순열 함수 호출
//완전탐색할 순열 함수
function getPermutation(arr, fixed) {
//매개변수 arr의 요소가 있을때까지만 반복 (사실상 이부분을 이해하는 것이 중요 -> 요소가 없다면 백트래킹이 적용되므로)
if (arr.length > 0) {
//arr의 각 요소에 대해
for (let i = 0; i < arr.length; i++) {
const newFixed = fixed + arr[i]; //기존의 고정값에 배열의 요소를 하나씩 붙이며 고정값을 늘려나감 -> 이렇게 늘려나가면서 arr.length > 0 일 때 까지 반복하는 것
const copyArr = [...arr]; //백트래킹으로 다시 돌아오려면 arr원본이 필요하기 때문에 arr의 복사본으로 다음 진행
copyArr.splice(i, 1); //기존 fixed에 newFixed로 붙여진 arr[i]는 제거하기 (이렇게 되면 copyArr에는 고정되지 않은 요소들이 남게됨)
//새로운 고정값은 소수 판별 후 맞으면 정답 set에 add
if (isPrime(parseInt(newFixed)) === true)
answer.add(parseInt(newFixed));
//재귀를 통해 배열의 요소가 없을 때까지 계속 고정값을 늘려가며 순열 구하기
getPermutation(copyArr, newFixed);
}
}
}
//소수 판별 함수
function isPrime(num) {
if (num < 2) return false; //2보다 작은 수 중에 소수는 없다
//2부터 num-1의 수 중에서 num으로 나누어떨어지는 수가 있다면 소수가 아니다
for (let i = 2; i < num; i++) {
if (num % i === 0) return false;
}
//그 외에는 true를 return
return true;
}
return answer.size; //정답 set에 들어있는 소수들의 크기로 return
}

 

후기


  • 결론부터 말하자면 이 문제는 내힘으로 풀진 못했고, 다른 분의 풀이를 봤지만 이해가 한 번에 되지않아 이틀에 걸쳐 이해를 하게됐다. 나름대로 순열을 이해하고 있다고 생각했는데, 이 문제를 풀면서 제대로 이해하고 있지 못한 내 상태를 알게됐고, 풀이를 보고도 제대로 이해가 안되는 내 자신이 너무 답답했다ㅜㅜ
  • 연습장에 과정을 하나하나 손으로 써가며 복기해보니 비로소 이해하게 되었고, 내가 가장 이해가 안 갔던 부분이 백트래킹 부분이었다는 것을 알게 되었다.
  • 참고로, https://sumin-k.medium.com/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-javascript-%EC%99%84%EC%A0%84-%ED%83%90%EC%83%89-%EC%86%8C%EC%88%98-%EC%B0%BE%EA%B8%B0-1fdcdca4f59b 풀이는 이블로그를 참고하였다.
  • 위 그림에서 4)번째 과정이 이해가 안되는 부분이었는데, 직전 과정을 통해 copyArr=[]가 되어, 재귀함수의 매개변수로 빈 배열이 주어졌기 때문에 코드의 if (arr.length > 0) 부분에서 false가 발생하여 백트래킹이 적용되어 2)번째 과정으로 돌아가 i=0에서 i=1로 바뀐 for문이 진행되는 것이다.
  • 그림의 왼쪽 상단 트리 구조는, 구조만 보면 이해는 갔으나 (빨간색이 fixed) 저 트리 구조만 보고 코드를 이해하는 데는 한계가 있었다. 그래서 하나하나 과정을 써가며 트리 구조와 함께 이해하니 코드가 이해됐다.
  • 생각보다 몇 줄 안되는 코드였지만 많은 것을 배운 문제였다.

잘못된 내용이나 수정이 필요한 내용이 있으면 언제든 댓글 달아주세요 감사합니다 😀
728x90

문제


https://www.acmicpc.net/problem/1357

 

1357번: 뒤집힌 덧셈

어떤 수 X가 주어졌을 때, X의 모든 자리수가 역순이 된 수를 얻을 수 있다. Rev(X)를 X의 모든 자리수를 역순으로 만드는 함수라고 하자. 예를 들어, X=123일 때, Rev(X) = 321이다. 그리고, X=100일 때, Rev(

www.acmicpc.net

 

코드


//브론즈1 뒤집힌 덧셈
const fs = require("fs");
const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
let input = fs.readFileSync(filePath).toString().trim().split("\r\n");
input = input[0].split(" "); // ['123', '100']
const answer = reverse(input[0]) + reverse(input[1]);
console.log(reverse(String(answer)));
function reverse(str) {
return parseInt(str.split("").reverse().join("")); // '123' -> '1','2','3' -> '3','2','1' -> '321'(string) -> 321(number)
}

 

후기


  • reverse 함수를 알고, split, join만 적절히 이용하면 쉽게 풀 수 있는 문제였다
  • 이해를 돕기위해 reverse() 함수의 과정을 예시로 적어놓았다
728x90

문제


https://programmers.co.kr/learn/courses/30/lessons/12924?language=javascript 

 

코딩테스트 연습 - 숫자의 표현

Finn은 요즘 수학공부에 빠져 있습니다. 수학 공부를 하던 Finn은 자연수 n을 연속한 자연수들로 표현 하는 방법이 여러개라는 사실을 알게 되었습니다. 예를들어 15는 다음과 같이 4가지로 표현 할

programmers.co.kr

 

코드


function solution(n) {
let answer = 0; //정답이 될 변수
let i = 1; //1부터 n까지 하나씩 오르는 변수
while (i <= n) {
let j = i; //현재 i를 copy
let copy = n; //n을 copy
while (copy > 0) {
//copy 즉, n이 양수일 동안
copy = copy - j; //연속된 수 j를 하나씩 빼주기
j++; //ex) 15 = 15-1 -> 14 = 14-2 -> 12 = 12-3 -> 9 = 9-4 ...
}
i++; //i를 +1 해줘서 다음 수부터 연속되는 수에대해서 또 찾기
if (copy === 0) answer++;
//두번째 while문을 통해서 나온 copy가 0이라면 연속된 j 수들의 덧셈에 의해 0으로 떨어진 것이니 정답 +1
else continue; //0으로 떨어지지 않았다면 i로 시작된 연속된 수는 n을 만들 수 없다는 의미니까 그냥 continue
}
return answer;
}

 

후기


  • 문제 유형이 적혀있진 않았지만 그리디 알고리즘을 생각하며 풀어보았다
  • i, j, n, copy 등 여러 변수들이 짧은 코드안에 복잡하게 등장했는데 각 쓰임새만 안 헷갈리면 쉽게 풀 수 있는 문제였다
  • 하지만 좀 더 효율적인 방법이 있을 것 같다..
728x90

문제


https://www.acmicpc.net/problem/1436

 

1436번: 영화감독 숌

666은 종말을 나타내는 숫자라고 한다. 따라서, 많은 블록버스터 영화에서는 666이 들어간 제목을 많이 사용한다. 영화감독 숌은 세상의 종말 이라는 시리즈 영화의 감독이다. 조지 루카스는 스타

www.acmicpc.net

 

코드


//실버5 영화감독 숌
const fs = require("fs");
const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
let input = fs.readFileSync(filePath).toString().trim().split("\r\n");
let end = 665; //종말의 수 처음인 666직전의 수로 초기화
input = input.shift(); //몇 번째 종말의 수를 찾을지
//input이 0이 아닐때까지
while (input > 0) {
end++; //665에서 +1 씩 늘리면서
if (String(end).includes("666")) input--; //"666"을 포함하는지 체크
}
console.log(end); //n번째 종말의 수 출력

 

후기


  • 나는 맨처음 이문제 접근을 규칙을찾자! 하고 규칙을 찾으려 했고.. 규칙같은 규칙을 찾았을 땐 실버5맞아이거? 왜이리어려워 했는데 이렇게 간단한 방법이 있었다.. 다른 분들의 풀이를 보고 역시 완전탐색은 어렵기도하고 또 단순히 생각해야 답이 나오는 것 같기도 하다
728x90

문제


https://www.acmicpc.net/problem/1018

 

1018번: 체스판 다시 칠하기

첫째 줄에 N과 M이 주어진다. N과 M은 8보다 크거나 같고, 50보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에는 보드의 각 행의 상태가 주어진다. B는 검은색이며, W는 흰색이다.

www.acmicpc.net

 

코드


//실버5 체스판 다시 칠하기
const fs = require("fs");
const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
let input = fs.readFileSync(filePath).toString().trim().split("\r\n");
//검정색이 맨처음 오는 경우
const blackFirst = [
"BWBWBWBW",
"WBWBWBWB",
"BWBWBWBW",
"WBWBWBWB",
"BWBWBWBW",
"WBWBWBWB",
"BWBWBWBW",
"WBWBWBWB",
];
//하얀색이 맨처음 오는 경우
const whiteFirst = [
"WBWBWBWB",
"BWBWBWBW",
"WBWBWBWB",
"BWBWBWBW",
"WBWBWBWB",
"BWBWBWBW",
"WBWBWBWB",
"BWBWBWBW",
];
const NM = input
.shift()
.split(" ")
.map((i) => parseInt(i));
const N = NM.shift(); //세로길이(y축)
const M = NM.shift(); //가로길이(x축)
let arr = [];
function blackFirstPaint(y, x) {
let count = 0; //몇 번이 바뀌는지 count할 변수
//8x8행렬의 크기에 한해서 미리 선언해놓은 8x8 행렬과 같지 않은 부분은 count++
for (let i = y; i < y + 8; i++) {
for (let j = x; j < x + 8; j++) {
if (input[i][j] !== blackFirst[i - y][j - x]) count++;
}
}
return count;
}
function whiteFirstPaint(y, x) {
let count = 0; //몇 번이 바뀌는지 count할 변수
//8x8행렬의 크기에 한해서 미리 선언해놓은 8x8 행렬과 같지 않은 부분은 count++
for (let i = y; i < y + 8; i++) {
for (let j = x; j < x + 8; j++) {
if (input[i][j] !== whiteFirst[i - y][j - x]) count++;
}
}
return count;
}
//8x8모양이 체스판의 가로, 세로를 넘지않는 모든 경우에 대해
// i : y축(N), j : x축(M)
for (let i = 0; i + 7 < N; i++) {
for (let j = 0; j + 7 < M; j++) {
arr.push(blackFirstPaint(i, j)); //모든 경우의 수에 대해 count를 세본다
arr.push(whiteFirstPaint(i, j));
}
}
console.log(Math.min(...arr)); //모든 경우의 수 중에서 가장 작은 값을 return

 

후기


  • 정답이되는 체스판을 미리 선언해놓고 완전탐색을 통해 하나하나 비교하며 count++을 하였다
  • 다른 분들의 코드에 비해 그리 시간이나 메모리가 많이 잡아먹지는 않으나 좀 더 효율적인 방법이 있을 것 같긴하다

+ Recent posts