프로그래머스 | 문자열에서 가장 많이 등장하는 문자 찾기

chaen·2024년 1월 4일
post-thumbnail

📌 문제

알파벳으로 구성 된 문자열 s가 있을 때 이 문자열에서 가장 많이 등장하는 문자를 출력하세요. 만약 해당하는 문자열이 여러 개일 경우 사전순으로 먼저 나오는 문자를 출력하세요.

✨ 해결 방법

  1. 우선 해당 문자열은 알파벳으로 구성되어 있으므로 배열을 만들어 그 배열 내부에 공간을 26개 만들어야 합니다. (알파벳의 총 개수)

    new Array(26)은 공간이 26개 있는 배열을 만들어줍니다.
    fill(0)은 모든 공간을 0으로 채웁니다.
    fill 에 대한 참고 링크
let arr = new Array(26).fill(0);
  1. 그 후 각 인덱스를 알파벳 문자에 매칭시키기 위해 각 문자를 ASCII 코드를 이용하여 알파벳 인덱스로 변환해야 합니다. .charCodeAt(index)를 활용합니다. 예를 들어, 'a'의 ASCII 코드는 97이고, 'z'의 ASCII 코드는 122입니다.
    charCodeAt과 charAt 참고 링크

  2. 각 문자열의 갯수가 세어졌다면, Math.max()를 사용하여 최대 값을 찾습니다.

Math.max(10,-10) // 10
var A = [ 1, 2, 4, 5 ]
Math.max(A); // 5

Math.max(...array_name); // 해당 배열에서 최대 값을 갖는 인덱스
  1. 사전순으로 가장 앞선 문자를 찾기 위해 문자열을 순회하면서 최대 값과 비교한 후, 해당 인덱스를 문자열로 변환합니다.

💻 solution

function solution(s) {
    var answer = ''; //가장 많이 등장하는 문자
    let arr = new Array(26).fill(0);
    // 알파벳 소문자 26개에 대한 배열

    for (let char of s){
        arr[char.charCodeAt(0) - 'a'.charCodeAt(0)]++;
    }

    let max = Math.max(...arr); // 최대 빈도수 찾기

    for (let i = 0; i < arr.length; i++) {
        if (arr[i] === max) {
            answer = String.fromCharCode(i + 'a'.charCodeAt(0)); // 가장 많이 등장한 문자
            break; // 최대 빈도수를 가진 문자를 찾았으므로 반복문 종료
        }
    }
    return answer;
}
  1. arr이라는 새 배열을 선언했을 때, 그 내부의 형태는 아래와 같습니다.
    [ 0, 0, 0, .....(*21), 0, 0 ]

  1. s 라는 문자열 안에 char이라는 문자가 포함될 때, 각 문자를 꺼내어 확인합니다. 이때 배열의 인덱스는 0부터 시작하기 때문에 a의 아스키 값을 빼서 해당 문자가 알파벳 중 어디에 위치하는지를 알아냅니다.

    예를 들어, 'a'는 'a'.charCodeAt(0) - 'a'.charCodeAt(0)) = (97 - 97) = 0 으로 arr[0]에 빈도수를 누적시키게 됩니다. 'b'는 'b'.charCodeAt(0) - 'a'.charCodeAt(0)) = (98 - 97) = 1이 되어 arr[1]에 빈도수를 누적시킵니다.

  1. max라는 변수를 선언하여 가장 많이 등장하는 문자를 찾습니다.

  1. for 문을 통해 반복을 실행한 후, 해당 인덱스 key 값이 max 값과 같을 때 ASCII 코드 값을 변환하여 해당 문자(answer)을 구합니다.

    i + 'a'.charCodeAt(0)는 현재 반복 중인 인덱스 i에 알파벳 'a'의 ASCII 코드 값을 더하여, 알파벳 문자열에서의 해당 문자의 ASCII 코드 값을 계산합니다. (예 -> 인덱스 5 : 102

    String.fromCharCode() 함수에 값이 전달되면, 해당 ASCII 코드에 해당하는 문자를 반환합니다.

💻 solution2

function solution(s) {
    var answer = '';
    let arr= new Array(26).fill(0);
    let max = 0;

    for (let char of s){
        arr[char.charCodeAt(0) - 'a'.charCodeAt(0)]++;
    }

    for (let i=0; i<arr.length; i++){
        if (arr[i] > max) {
            max = arr[i];
            answer = String.fromCharCode(i + 'a'.charCodeAt(0));
        }

    }


    return answer;
}

Math.max() 를 활용하지 않고 바로 썸으로 찾아내는 방법도 있습니다.
만약 인덱스의 key 값이 max의 초기값인 0보다 클 경우 초기 값을 key 값으로 설정하고, 해당 key 값을 변환하여 문자열 (정답)으로 만듭니다. 이를 전체 배열에서 순환하면서 더 큰 key 값이 나온다면 max 값을 다시 바꾸고, 정답도 다시 바꾸는 작업을 반복합니다.

두 번째 방법은 문자열을 한 번만 순회하여 최대 빈도수를 찾아내는 점에서 더욱 효율적입니다.

👍 사전식 나열이 필요 없을 때의 방법

function solution(s) {
    var answer = '';
    let arr= new Array(26).fill(0);
    let max = 0;

    for (let char of s){
        arr[char] = arr[char] ? arr[char] + 1 : 1;
    }

    for (let char in arr){
       if (arr[char] > max){
           max = arr[char];
           answer = char;
       } 

    }
    return answer;
}

해결 방법 2와 거의 유사하지만, 사전식 순서가 아닌 문자열에서 먼저 나오는 문자 순으로 선정됩니다.
사전식 나열이 필요 없을 경우 굳이 아스키 코드로 바꾸지 않고 값을 구할 수 있습니다.

해결식 2와 다른 부분을 설명해보자면 아래와 같습니다.

arr[char] = arr[char] ? arr[char] + 1 : 1;

//아래와 같습니다
if (arr[char]) { // 해당 인덱스의 key 값이 있을 경우
  arr[char] = arr[char]++; //key 값이 1 증가한다.
} else {
  arr[char] = 1; // 없을 경우 key 값에 1을 부여한다.
}

0개의 댓글