1부터 n까지 번호가 붙어있는 n명의 사람이 영어 끝말잇기를 하고 있습니다. 영어 끝말잇기는 다음과 같은 규칙으로 진행됩니다.
다음은 3명이 끝말잇기를 하는 상황을 나타냅니다.
tank → kick → know → wheel → land → dream → mother → robot → tank
위 끝말잇기는 다음과 같이 진행됩니다.
끝말잇기를 계속 진행해 나가다 보면, 3번 사람이 자신의 세 번째 차례에 말한 tank 라는 단어는 이전에 등장했던 단어이므로 탈락하게 됩니다.
사람의 수 n과 사람들이 순서대로 말한 단어 words 가 매개변수로 주어질 때, 가장 먼저 탈락하는 사람의 번호와 그 사람이 자신의 몇 번째 차례에 탈락하는지를 구해서 return 하도록 solution 함수를 완성해주세요.
제한 사항
n | words | result |
---|---|---|
3 | ["tank", "kick", "know", "wheel", "land", "dream", "mother", "robot", "tank"] | [3,3] |
5 | ["hello", "observe", "effect", "take", "either", "recognize", "encourage", "ensure", "establish", "hang", "gather", "refer", "reference", "estimate", "executive"] | [0,0] |
2 | ["hello", "one", "even", "never", "now", "world", "draw"] | [1,3] |
입출력 예 #1
3명의 사람이 끝말잇기에 참여하고 있습니다.
입출력 예 #2
5명의 사람이 끝말잇기에 참여하고 있습니다.
입출력 예 #3
2명의 사람이 끝말잇기에 참여하고 있습니다.
function solution(n, words) {
for (let i = 0; i <= words.length; i++) {
if (i === 0) continue; // 첫 번째 단어인 경우 바로 다음 인덱스 순회함
if (i === words.length) return [0, 0]; // 마지막 단어인 경우 탈락자가 생기지 않았음을 의미
const prevWord = words[i - 1]; // 이전 단어
const nextWord = words[i]; // 현재 단어
const wrongWord = prevWord[prevWord.length - 1] !== nextWord[0]; // 끝말잇기에 실패했을 경우
const sameWord = words.indexOf(nextWord) !== i; // 동일한 단어를 말했을 경우
if (wrongWord || sameWord) {
const currentWordOrder = i + 1;
const value = currentWordOrder % n;
const eliminationNumber = value ? value : currentWordOrder / n;
const eliminationOrder = Math.ceil(currentWordOrder / n);
return [eliminationNumber, eliminationOrder]
}
}
}
테스트 케이스 4문제를 통과하지 못했다. 원인을 찾기 위해 내가 놓친 조건이 있나 문제를 다시 꼼꼼하게 읽어봤다.
function solution(n, words) {
for (let i = 0; i < words.length; i++) {
if (i === 0) continue; // 첫 번째 단어인 경우 바로 다음 인덱스 순회함
const prevWord = words[i - 1]; // 이전 단어
const nextWord = words[i]; // 현재 단어
const wrongWord = prevWord[prevWord.length - 1] !== nextWord[0]; // 끝말잇기에 실패했을 경우
const sameWord = words.indexOf(nextWord) !== i; // 동일한 단어를 말했을 경우
if (wrongWord || sameWord) {
const currentWordOrder = i + 1;
const value = currentWordOrder % n;
const eliminationNumber = value ? value : currentWordOrder / n;
const eliminationOrder = Math.ceil(currentWordOrder / n);
return [eliminationNumber, eliminationOrder]
}
}
return [0,0] // 끝말잇기에 성공했을 경우
}
마지막 인덱스인 경우에 마지막 단어가 끝말잇기에 실패했는지 여부를 판단하지 않고 바로 [0, 0]
를 return하기 때문에 여기서 문제가 생길 수 있다고 판단하고 return문을 for문 바깥으로 이동하는 방식으로 풀이를 수정했다. 하지만 변함없이 4개의 테스트 케이스를 통과하지 못하고 있다.
function solution(n, words) {
for (let i = 0; i < words.length; i++) {
if (i === 0) continue; // 첫 번째 단어인 경우 바로 다음 인덱스 순회
const prevWord = words[i - 1]; // 이전 단어
const nextWord = words[i]; // 현재 단어
const wrongWord = prevWord[prevWord.length - 1] !== nextWord[0]; // 끝말잇기에 실패했을 경우
const sameWord = words.indexOf(nextWord) !== i; // 동일한 단어를 말했을 경우
if (wrongWord || sameWord) {
return [i % n + 1, Math.floor(i / n) + 1];
}
}
return [0,0] // 끝말잇기에 성공했을 경우
}
끝말잇기에 실패했을 경우에 if문에서 배열을 return하는 부분을 전체적으로 수정했다. 기존에는 if문 안에서 변수도 많이 선언하고 삼항연산자도 사용했었는데 return문 한 줄로 수정하여 더욱 가독성 좋은 코드를 만들었다.
continue
를 사용하여 바로 다음 인덱스로 이동한다.wrongWord
변수에 boolean
형태를 할당한다.indexOf
메서드를 이용하여 배열 안에서 해당 단어를 가진 첫 번째 인덱스와 현재 인덱스가 다를 경우를 boolean
형태로 sameWord
변수에 할당한다.wrongWord
와 sameWord
둘 중에 하나가 true인 경우, 가장 먼저 탈락하는 사람의 번호와 그 사람이 자신의 몇 번째 차례에 탈락했는지를 담은 배열을 return한다.wrongWord || sameWord
if문에 해당하지 않았다면 탈락자가 발생하지 않은 것이므로 [0,0]
를 return한다.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
메서드의 특성을 활용한 재미있는 풀이 방법이었다. 끝말잇기에 실패하는 경우에는 해당 index
를 answer
에 할당한다. 그리고 prev
누적값에는 다음 단어에서 끝말잇기에 성공했는지를 판단하는데 이용하기 위해 현재 단어의 마지막 글자를 할당한다.
근데 해당 풀이에서는 끝말잇기에 실패하더라도 reduce
함수를 종료하지 않고 모든 요소를 순회하기 때문에 효율성 측면에서 좋은 답변인지는 잘 모르겠다.