프로그래머스 | 영어 끝말잇기

Autumn·2020년 12월 22일
0

알고리즘

목록 보기
1/6
post-thumbnail

문제 바로가기

코드

function solution(n, words) {
  const existSameWord = (words) => {
    const set = new Set();
    for(let i = 0; i < words.length; i++) {
      if(set.has(words[i])) return words[i];
      !set.has(words[i]) && set.add(words[i])
    }
    return false
  }
  
  const verifyWordChain = (words) => {
    for(let i = 1; i < words.length; i++) {
      const prevWord = words[i - 1];
      const currWord = words[i];
      if(currWord.length === 1) return i
      if(prevWord[prevWord.length - 1] !== currWord[0]) return i
    }
    return true
  }
  
  const getTurn = (idx) => { // 사람들 중 몇번째 순서인지
    return ((idx + 1) % n === 0 ? n : (idx + 1) % n)
}
  
  const getNthTurn = (idx) => { // 내 차례가 몇번 돌아왔는지
    return Math.ceil((idx + 1) / n)
  }
  
  // 탈락자 없는 조건 먼저 걸어주기
  if(existSameWord(words) === false && verifyWordChain(words) === true) return [0, 0]
  
  if(existSameWord(words) !== false) { // 같은 단어가 있다는 뜻!
    const repeatedWord = existSameWord(words);
    const idxOfRepeated = words.lastIndexOf(repeatedWord);
    return [getTurn(idxOfRepeated), getNthTurn(idxOfRepeated)]
  }
  
  if(verifyWordChain(words) !== true) { // 끝말잇기를 틀리게 한 사람 존재
    const idxOfWrongWord = verifyWordChain(words);
    return [getTurn(idxOfWrongWord), getNthTurn(idxOfWrongWord)]
  }
}

풀이 방법

문제에 정답 리턴값이 하나인 것으로 보아 어떤 경우든 탈락자가 2명 이상 나오지 않을 것이라는 것을 염두에 두고 탈락하는 경우를 나누어보았다.

  1. 앞에 나왔던 단어를 또 말한 경우
  2. 끝말을 잇지 못한 경우
  3. 한글자 단어인 경우 (예: a)

코드를 작성하기 전에 함수를 최대한 쪼개어보기로 마음먹었다. 코드가 복잡해보이지만 함수 4개와 실행부 조건 3개로 이루어져 있다.


함수

  • existSameWord
    (경우 1) 같은 단어가 존재하는지 확인하는 함수. Set 객체를 하나 만들어서 배열의 원소를 차례대로 넣어준다. Set 객체에 넣기 전에 Set의 has() 메서드를 이용하여 단어가 이미 앞에서 나온 단어인지 확인하고, 있으면 그 단어를 바로 리턴, 없으면 Set 객체에 단어를 추가. for문이 모두 끝나면 중복 단어가 없다는 뜻이므로 false를 리턴

처음에는 const set = new Set(words) 라고 작성 후 set 의 길이와 words 의 길이만 비교해서 중복 값이 있는지 없는지 체크했는데, 답을 구하려면 어떤 단어가 중복됐는지를 알아야 words 배열에서의 인덱스를 알아낼 수 있으니 방법을 위와 같이 바꾸었다.

  • verifyWordChain
    (경우 2 & 3) 끝말이 제대로 이어지는지 확인하는 함수. for문 이용해서 이전 단어의 끝 글자와 현재 단어의 첫 글자 비교. 끝말을 잘 받았어도 한글자이면 탈락이기에 끝말 확인 전에 단어 길이가 1인지를 우선 확인. 단어 길이가 1이거나 끝말잇기가 제대로 안 된 경우 인덱스를 리턴하고, 정상적으로 for문이 끝난다면 끝말이 제대로 이어졌다는 뜻이므로 true를 리턴

어쨌거나 탈락하는 사람이 2명 이상 나오지 않는다는 게 포인트!!

  • getTurn
    n명의 사람들 중 내가 몇번째 순서인지 구하는 함수. 위에 두 함수에서 받은 리턴값을 활용해 구한다.

  • getNthTurn
    내 차례가 몇 번 돌아왔는지 구하는 함수. 역시 위에 두 함수에서 받은 리턴값을 활용해 구한다.


실행부

  1. 우선 탈락자가 없는 조건 먼저 걸어준다.
  2. 같은 단어가 있는 경우 - existSameWord 함수를 이용해 중복되는 단어를 알아낸 뒤, words 배열에 제일 마지막에 나오는 해당 단어가 바로 탈락 지점임을 이용해 정답을 구한다.
  3. 끝말잇기를 틀리게 한 경우 - verifyWordChain 함수를 이용해 틀린 지점의 인덱스를 구하고 그것을 이용해 정답을 구한다.

생각해볼 점

함수에서 리턴값이 일관되게 true/false처럼 나와야할 것 같은데 저렇게 조건에 따라 어떨 때는 인덱스 반환하고 어떨 때는 true 를 반환하는 게 맞는 건지 모르겠다. 그리고 함수 이름이랑 리턴값이 잘 매치가 안 되는 부분도 있는 것 같다. 이름 짓기 넘 어려워~~~ 함수를 최대한 잘게 쪼개보는 게 목표였는데 다른 사람들 풀이 보니까 코드가 훨씬 짧아서 또 내가 푼 방법이 맞나 의문이 들기도 했다.

아! 어제 코어자바스크립트 책 공부한 내용에서 함수 선언식으로 작성 시 호이스팅 때문에 오류를 쉽게 찾을 수 없을 수도 있다는 점 때문에 앞으로는 화살표 함수를 사용한 표현식으로 다시 쓰려고 한다.

끝!

profile
한 발짝씩 나아가는 중 〰 🍁 / 자잘한 기록은 아래 🏠 아이콘에 연결된 노션 페이지에 남기고 있어요 😎

0개의 댓글