https://school.programmers.co.kr/learn/courses/30/lessons/12981#
최근 나의 풀이
문제 풀기전 생각했던 것들
// 문제
/*
1부터 n 까지 n명의 사람이 영어 끝말잇기를 한다.
이전에 등장했던 단어 x
한 글자인 단어 x
return [number, number]
return [가장 먼저 탈락하는 사람의 번호, 그 사람이 자신의 몇 번째 차례에 탈락하는지]
*/
// 제한
/*
n 참여자수 2~10
arr.length n이상 100이하
단어의 길이 2이상 50이하
소문자로만
단어의 뜻 상관 x
[번호, 차례]
예외 - 탈락자 없을 시 [0,0]
*/
// 설계
/*
기존에 나왔던 단어들 set에 넣고 has를 사용해서 체크 가능
굳이 배열을 다 순회할 필요가 없는 문제이기 때문에
forEach나 reduce보다 for문은 사용해서 조건에 맞지않으면 바로 return
*/
function solution(n, words) {
const usedWords = new Set([words[0]])
let beforeLastLetter
// 총 3번의 return 존재
/*
1. 끝말잇기가 성립되지 않을 때
2. 이미 사용했던 단어를 또 사용했을 때
3. 탈락자가 발생하지 않았을 때 (for문은 다 순회하고 return이 되지 않으면 탈락자가 없다는 뜻)
*/
for(let i = 1; i<words.length; i++){
beforeLastLetter = words[i-1].at(-1)
if(beforeLastLetter !== words[i][0]){
return [((i+1) % n) || n, Math.ceil((i+1) / n)]
}
if(usedWords.has(words[i])){
return [((i+1) % n) || n, Math.ceil((i+1) / n)]
}
usedWords.add(words[i])
}
return [0,0]
}
과거 나의 풀이
1)
function solution(n, words) {
let count = 0
words.reduce((acc,cur,i,arr) => {
if(i !== 0){
if( cur[0] !== acc[i-1][acc[i-1].length - 1]){
count = i + 1
return arr.splice(1)
}
if(acc.includes(cur)){
count = i + 1
return arr.splice(1)
}
}
acc[i] = cur
return acc
},[])
let order
if(count <= n ) order = count
else{
if ((count % n) === 0) order = n
else order = count % n
}
return count ? [order, Math.ceil(count / n)] : [0,0];
}
for문으로 풀까 reduce로 풀까 생각하다 효율성 테스트가 없어서 reduce로 풀기로하였다.
(과거의 생각을 본 현재 나의 생각 : 아니지 조건에 맞지 않으면 바로 return 을 해야하기 때문에 for문이 훨씬 더 좋지 굳이 reduce를 사용해가면서 중단하기 위해 splice를 사용할 이유가 있을까?)
먼저 reduce로 첫항이 아닐때
첫번째 if문은 현재 단어 첫번째 알파벳과 이전 단어 마지막 알파벳이 같은지 확인하는 작업이다.
만약 끝말잇기가 이어지지 않으면 count에 현재 인덱스 + 1을 넣어준뒤 splice(1)을 통해 즉시 reduce를 중단시킨다.
두 번째 if문은 현재 단어 이전까지의 모든 단어들이 들어있는 acc배열에서 현재 단어가 발견된다면 중복적용이 안되기에 이 역시 즉시 reduce를 중단시킨다.
만약 if문에 하나도 걸리지 않는다면 reduce는 전체를 돌고나도 box = 0 이된다.
그런뒤 첫 번째 탈락자의 번호와 차례를 출력해줘야한다.
여기서 조금 시간이 걸렸다.
1. count <= n일때
1) count < n일때
먼저 count는 첫 번째 단어가 1이고 마지막 단어가 n번째이다.
만약 n = 10이고 count = 5이면 끝말잇기 참여자수는 10명인데 첫 번째 차례에 5번이 탈락한 것이다.
따라서 번호는 count < n 이기에 count 자체가 순서이다.
차례는 count / n = 5 / 10 = 0.2 를 올림하면 = 1 (차례)
2) count = n 일때
만약 n =10이고 count = 10이면 끝말잇기 참여자수는 10명인데 첫 번째 차례에서 1번이 탈락한 것이다.
따라서 번호는 count = n 이기에 n 또는 count가 "번호"이다.
차례는 count/n = 10/10 = 1 (차례)
2. count > n 일때
1) count % n ===0 일때
만약 n = 3 이고 count = 9이면 끝말잇기 참여자수는 3명인데 세 번째 차례에서 3번이 탈락한 것이다.
따라서 번호는 count > n 이지만 count % n === 0이기에(9 % 3 = 0) n이 번호가 된다.
2) 그외에경우
만약 n = 10 이고 count = 11 이면 끝말잇기 참여자수는 10명인데 두 번째 차례에서 1번이 탈락한 것이다.
따라서 번호는 count > n 이기에 count % n = 11 % 10 = 1 (번호)
차례는 count/ n = 11/10 = 1.xxx 올림하면 = 2(차례)
2)
function solution(n, words) {
let count = 0
words.reduce((acc,cur,i,arr) => {
if(i !== 0){
if( cur[0] !== acc[i-1][acc[i-1].length - 1]){
count = i
return arr.splice(1)
}
if(acc.includes(cur)){
count = i
return arr.splice(1)
}
}
acc[i] = cur
return acc
},[])
return count ? [count%n+1, Math.floor(count / n)+1] : [0,0];
}
count + 1을 하지말고 그냥 index그대로 가져오면 훨씬 편하다
다른 사람 풀이
function solution(n, words) {
let answer = 0;
words.reduce((prev, now, idx) => {
answer = answer || ((words.slice(0, idx).indexOf(now) !== -1 || prev !== now[0]) ? idx : answer);
return now[now.length-1];
}, "")
return answer ? [answer%n+1, Math.floor(answer/n)+1] : [0,0];
}
나보다 훨씬 reduce를 더 잘 활용한 것같다.
특히 마지막 return부분이 인상적이다.
필자가 처음에 했던 count = i + 1 대신 count = i로 해주는게 나중 계산에 훨씬 편리한듯 싶다.
'알고리즘 > 프로그래머스 - JS' 카테고리의 다른 글
[프로그래머스 - JS] level.2 뒤에 있는 큰 수 찾기 📌⭐️⭐️ (0) | 2023.07.03 |
---|---|
[프로그래머스 - JS] level.2 파일명 정렬 📌⭐️ (0) | 2023.07.02 |
[프로그래머스] level.2 모음사전 (0) | 2023.06.29 |
[프로그래머스-JS] level.2 스킬 트리 (0) | 2023.06.28 |
[프로그래머스] level.2 방문 길이 (0) | 2023.06.28 |