이 문제는 이상하게 계속 풀리지 않는다.. for문을 삼중으로 사용하여 테스트 케이스를 통과했지만
본 채점을 하면 0점이 나온다. 이유는 런타임 에러 .. 그런데 예전에 내가 풀었던 풀이를 보면 같은 방법으로
풀었는데 그 코드는 통과하고 이번에 필자가 푼 코드는 통과를 하지 못한다.. 1시간 넘게 고민하다 결국 이 문제는 놓아주었다.
다른 분들의 코드를 보며 학습할 기회라고 생각하겠다!!!!
먼저 예전에 내가 통과를 받았던 코드이다.
function solution(arr1, arr2) {
let answer =[]
for (i = 0; i < arr1.length; i++) {
let answers =[]
let count = arr2[1].length;
for (j = 0; j < count; j++) {
let sum = 0;
for (k = 0; k < arr2.length; k++) {
sum = sum + arr1[i][k] * arr2[k][j];
}
answers.push(sum)
}
answer.push(answers)
}
return answer
}
아래 코드는 이번에 실패를 받은 코드이다.
function solution(arr1, arr2) {
const arr2Length = arr2[0].length;
let answer = [];
for (let i = 0; i < arr1.length; i++) {
let arr = [];
for (let j = 0; j < arr2[0].length; j++) {
let sum = 0;
for (let k = 0; k < arr2Length; k++) {
sum = sum + arr1[i][k] * arr2[k][j];
}
arr.push(sum);
//index1 이 2까지 인데 arr2의 내부 arr은 1까지임
}
answer.push(arr);
}
return answer;
}
코드에서 다른 점을 수정하며 어떤 부분에서 통과/불통과가 나누어졌는지 분석했다.
차이는 k for문에서 k의 범위를 결정해주는 부분에서 arr2.length로 해야하는데 arr2[0]으로 범위를 설정해준 부분에서 에러가 발생했다. 결국 런타임 에러 보다는 그냥 풀이를 잘못 푼것이다...
이렇게 풀었지만 사실 for문을 3개나 쓰기도 했고 한눈에 보기에 복잡해보여 좋은 코드로 판단되지 않는다.
그래서 다른 분들의 코드를 참고하여 학습했다.
다른 분들의 코드도 대부분 for문을 3개 사용하여 풀었지만 그 중 눈에 띄였던 부분은 map과 reduce를 사용한 풀이법이다.
function productMatrix(A, B) {
return A.map(function(row) {
return row.map(function(_, i) {
return row.reduce(function(sum, cell, j) {
return sum + cell * B[j][i];
}, 0);
});
});
}
map을 활용하여 arr1의 내부의 원소에 접근한다. 그 후 reduce 함수를 이용하여 내부 원소에 arr2의 행과 열의 인덱스를 집어 넣고 곱하며 더해주는 방식이다. 이런 생각을 할 수 있는게 참 신기하다..
reduce는 풀이를 접하다 보면 은근히 자주나오는 메서드라 꼭 잘 알고 사용을 해야겠다!
귤 고르기 문제는 종류를 최대한 같게 원하는 개수 담아줄 때 그 종류의 수를 return 하면 되는 문제이다.
먼저 두 가지를 생각했다.
- 같은 종류와 다른 종류를 어떻게 구별할까
- 구별 한 후 배열을 순회하며 k 만큼 담아주자
먼저 종류를 구분해야했다. 어떻게 구분을 해야할까
먼저 new Map을 떠올렸다. 만약 배열을 순회하며 숫자가 나왔을 때 그 숫자를 "key"값으로하고 count up을 하는 방법
new map은 다음과같이 사용한다.
const map1 = new Map()
map1.set('key',0)
//그리고 이 저장값에 count up을 하고싶다면
map1.set('key',map1.get('key`)+1)
// 이렇게도사용가능하다.
먼저 이렇게 하는 방법을 생각했는데 이 방법은 사용하지 않았다.
필자가 생각으로는 바로 그 숫자를 check하는 arr의 index로 사용하는 것이다.
new Map은 종류의 이름까지 알 수 있는 메서드이다. 하지만 위 문제는 종류의 개수만 알면되기때문에
종류를 구분하지 않고 그냥 종류가 같다면 같은 위치에 저장해주고싶었다.
그렇게 다음과 같은 로직을 생각했다.
let check = [];
let answerArr = [];
for (let i = 0; i < tangerine.length; i++) {
if (check.includes(tangerine[i]) === false) {
check.push(tangerine[i]);
answerArr[tangerine[i]] = 1;
continue;
}
answerArr[tangerine[i]] = answerArr[tangerine[i]] + 1;
}
각 요소가 숫자임으로 index로 사용이 가능하다. 그렇기 때문에 바로 check 라는 arr의 인덱스에
같은 숫자(인덱스)일 경우 해당 인덱스에 +1을 하여 넣어주었다.
그 후 이 배열을 sort하여 큰 순서대로 k를 제거해 나가면 몇 종류일 때 모두 귤을 골라줄 수 있는지 알 수 있다.
최종 코드는 다음과 같다.
function solution(k, tangerine) {
let check = [];
let answerArr = [];
for (let i = 0; i < tangerine.length; i++) {
if (check.includes(tangerine[i]) === false) {
check.push(tangerine[i]);
answerArr[tangerine[i]] = 1;
continue;
}
answerArr[tangerine[i]] = answerArr[tangerine[i]] + 1;
}
answerArr.sort((a, b) => b - a);
for (let j = 0; j < answerArr.length; j++) {
k = k - answerArr[j];
//k개씩 나누어주는 모습이다. 즉, answerArr은 같은 종류가 몇개있는지 담고있는 arr이기때문에
//위 요소를 제거한다는 건 같은 종류의 개수를 제거해 나가는 것과 같다.
if (k<=0) {
return j+1;
}
}
return 1;
//k가 0보다 클 경우는 나누어주는 k가 한 종류에서 k를 다 나누어 주었다는 말이기 때문에
// return 1을 해준다.
}
이 코드에서 아쉬운 점은 for문을 두 번 사용했다는 점이다.
사실 for문을 사용하지 않기 위해 reduce를 이용해보려 했는데 쉽지않았다..
answerArr.reduce((acc,cur,index)=>{
if(acc>=k){
return index+1
}
return index
},0)
이런 모습으로 문제를 해결하고 싶었는데 reduce의 사용법을 제대로 숙지하지 못했던 거 같다..
reduce는 결국엔 반복문이다.
이게 무슨 말이냐면
const test = [1,2,3,4]
const result = test.reduce((acc,cur,index)=>{
return acc+cur;
// 처음으로 한번순회할때는 result = 1
// 두 번째로 순회 result =3
// 세 번째로 순회 result =6
// 네 번째로 순회 result =10
/*
즉 매번 순회할 때 마다 그 return 값을 가지고 다시 순회한다 만약
if문을 걸어 특정 값만 return하고 싶다해도 그 값은 최종 return 값이
되는 것이 아니라 다음 순회를 위한 return값이 된다!
*/
})
즉, reduce에서 조건문은 다음 순회를 위한 특정 값 더하기 일 뿐이다. reduce문을 잘 사용하면 해당 문제를 풀 수도 있겠다고 생각이 들었다.
default return 값을 acc로만 해두고 특정 조건 일때만 acc+cur을 하면 최종 내가 원하는 acc를 얻을 수 있을 것이다.
가장 중요한건 return은 계속해서 이어나가진다는 점이다. 최종적으로 마지막 배열까지 돌아야 최종값을 저장한다.
위 문제는 복잡해보이지만 new Map을 사용해서 풀면 됐다.
옷의 종류는 Map의 key 값이되고 옷은 Map의 count value가 된다.
먼저 같은 이름의 의상은 없기 때문에 중복을 신경 쓸 필요없이 그냥 같은 종류의 옷이면 key 값에 추가해주었다.
그리고 그 map을 spread operator를 사용해서 array의 형태로 변경 후 배열을 순회하며 정답을 유도했다.
function solution(clothes) {
//new Map으로 풀자
const Box = new Map();
for (let i = 0; i < clothes.length; i++) {
if (Box.get(clothes[i][1]) === undefined) {
Box.set(clothes[i][1], 1);
continue;
}
Box.set(clothes[i][1], Box.get(clothes[i][1]) + 1);
}
const BoxArr = [...Box];
let answer = 1;
BoxArr.forEach((item) => {
answer = answer * (item[1] + 1);
// 이 부분은 사실상 수학공식이다.
});
return answer - 1;
}
위 문제는 카카오 인턴쉽 문제이다. 문제를 분석해보면 결국 어떤게 먼저 들어왔는지를 알아보는 문제이다.
즉 들어온 순서를 알 수 있어야한다. 필자는 위 문제를 해결하기 위해 로직을 다음과 같이 세웠다.
위 문제를 풀면서 가장 힘들었던 부분은 string을 array로 바꾸는 과정이었다.
split 메서드만 단순히 이해하고있었지 이를 제대로 활용해본건 이번 문제가 처음인거 같다.
split을 하기위해 불필요한 string을 잘라주고 다시 split을 한 뒤 map을 이용하여 이중배열을 생성했다.
코드는 다음과 같다 .
function solution(s) {
const stack = [];
let S = s
.slice(2, s.length - 2)
// splice는 원본에 영향을 주지 않음으로 S에 저장하였다.
.split(`},{`)
// 이렇게 변환시키면 [2, 2,3, 2,1,3 , 2,1,2,3 ]
.map((item) => item.split(`,`))
// map을 통해 내부의 , 를 기준으로 split 메서드를 이용하여 array형성
.sort((a, b) => a.length - b.length);
// 그 후 길이가 짧은 순서대로 이중 배열을 정돈
for (let i = 0; i < S.length; i++) {
for (let j = 0; j < S[i].length; j++) {
if (stack.includes(parseInt(S[i][j])) === false) {
stack.push(parseInt(S[i][j]));
// 그 후 stack에 넣어가며 비교
}
}
}
return stack;
}
다른 분들의 코드도 대부분 메서드만 다를 뿐 로직은 비슷하였다.
다만 slice에서
slice(2,s.length-2)//가 아닌
slice(2, -2) // 이렇게 사용한 부분을 보았다.
//-2를 넣으면 자동으로 뒤에서부터 2 만큼 의 길이를 잘라준다!!