본문 바로가기
개발자 일기/알고리즘 공부

[프로그래머스 JS] 옹알이 (2)

by MS_developer 2023. 8. 22.

📖 문제 설명

머쓱이는 태어난 지 11개월 된 조카를 돌보고 있습니다. 조카는 아직 "aya", "ye", "woo", "ma" 네 가지 발음과 네 가지 발음을 조합해서 만들 수 있는 발음밖에 하지 못하고 연속해서 같은 발음을 하는 것을 어려워합니다.

 

문자열 배열 babbling이 매개변수로 주어질 때, 머쓱이의 조카가 발음할 수 있는 단어의 개수를 return하도록 solution 함수를 완성해주세요.

 


🚫 제한 사항

  • 1 ≤ babbling의 길이 ≤ 100
  • 1 ≤ babbling[i]의 길이 ≤ 30
  • 문자열은 알파벳 소문자로만 이루어져 있습니다.

💾 입출력 예시

 

food result
["aya", "yee", "u", "maa"] 1
["ayaye", "uuu", "yeye", "yemawoo", "ayaayaa"] 2

 

 


⚠️ 유의사항

  • 네 가지를 붙여 만들 수 있는 발음 이외에는 어떤 발음도 할 수 없는 것으로 규정합니다. 예를 들어 "woowo"는 "woo"는 발음할 수 있지만 "wo"를 발음할 수 없기 때문에 할 수 없는 발음입니다.

⌨️ 나의 풀이 (코드)

 

코드 작성에 앞서 의사 코드를 작성했다.

1. babbling을 순회하며 각 단어를 확인
2. 각 단어들이 "aya", "ye", "woo", "ma"로만 이루어져 있는지 확인 (이 외 일치하지 않는 단어가 있다면 다른 단어가 있더라도 return값에 1을 더하지 않음) => 일치하는 음절이 있다면 해당 단어를 삭제
3. 요소(단어)에 일치하는 글자들로만 이루어져 모두 삭제되었다면 return값 +1

 

제목에서 알 수 있듯, 옹알이는 이전에 Level 0에서 풀어본 적 있는 문제다. 

 

단, 차이점이 있다면 이전 문제는 네 가지 발음을 최대 한 번씩 사용해 조합한(이어 붙인) 발음밖에 하지 못하는 제한이 있었지만, 이번 경우는 횟수에 제한이 없다. 

 

즉, 같은 단어를 여러 번 사용하는 경우도 고려해야 하므로 이전에 사용했던 방식과는 다르게 접근해야 한다는 것을 유의하고 코드를 작성했다.

 

function solution(babbling) {
    let answer = 0;
    const wordList = ["aya", "ye", "woo", "ma"];

    for(let i = 0; i < babbling.length; i++) {
        let temp = babbling[i];
        wordList.forEach(word => {
          if(babbling[i].includes(word)){
              temp = temp.replace(word,'');
          }
        })

        if(temp.length === 0) {
            answer++;
        }
    }
    return answer;
}

 

이전에 작성했던 코드를 기반으로 구현해 보았는데, 단어가 2번 이상 반복할 수는 없어도 각 단어가 한 번 이상 쓰일 수 있기 때문에 해당 로직으로는 문제 풀이가 불가능했다.

 

따라서 기존 방식에서 변화를 주어야 했다.

 

function solution(babbling) {
  let answer = 0;
  const wordList = ["aya", "ye", "woo", "ma"];

  for (babble of babbling) {
    for (let i = 0; i < wordList.length; i++) {
      if (!babble.includes(wordList[i].repeat(2))) {
        babble = babble.split(wordList[i]).join(" ");
      }
    }

    if (babble.split(" ").join("").length === 0) {
      answer++;
    }
  }
  return answer;
}

 

먼저 기존 단어가 반복되는 경우를 고려해 조건문을 통해 일차적으로 구분했다.

 

추가로 각 단어를 재조합하는 과정을 .replace() 메서드를 활용해 다시 구성하는 방식 대신 .split() 메서드를 활용해 일치하는 단어가 있다면 제외시킨 후 .join() 메서드를 활용해 다시 재결합하는 방식을 사용했다.

 

이때, .join() 메서드를 사용할 때 매개변수를 ""로 지정하면 기존 단어가 변경되기 때문에 " "로 구분하여 사용했다.

 

해당 과정이 모두 끝난 후 단어를 재조립했을 때 과정을 거친 배열 내에 요소가 없다면 해당 문자열의 길이가 0이므로 옹알이를 한 것으로 가정할 수 있다.

 

코드는 모든 테스트 케이스들을 무사히 통과할 수 있었다.


📝 Note

 

문자열 패턴을 검사할 때 보편적으로 쓰이는 정규 표현식을 사용하는 방법을 생각해보았지만, 사용하는데 어려움이 있어 결국 포기했다.

 

문제 풀이를 끝내고 다른 분의 블로그 풀이에서 서술된 정답이 있었다.

 

function solution(babbling) {
    let regexp = /(?<!aya)(aya)(?!aya)|(?<!ye)(ye)(?!ye)|(?<!woo)(woo)(?!woo)|(?<!ma)(ma)(?!ma)/g
    
    let result = babbling.reduce((acc, cur) => {
        if (cur.replace(regexp, '') === '') acc++
        return acc
    }, 0)
                                 
    return result
}

 

매우 강력한 코드였다.

 

위 코드에서 정규 표현식에 조금 더 배울 수 있는 계기가 되었다.

 

(?<!)는 부정형 후방탐색, (?!)는 전방형 후방탐색으로 해당 문자열 (i.e. (aya)의 전후방)을 탐색해 일치하지 않는 텍스트를 찾아낼 수 있는 문법이다.

댓글