강의

멘토링

커뮤니티

Inflearn Community Q&A

a939518771's profile image
a939518771

asked

The secret to passing 38 companies: Essential algorithms for the 2025 coding test

1-5. Getting Familiar with Algorithms (2)

1-5 알고리즘과 친해지기 (2) - 최빈값찾기 질문 있습니다

Written on

·

60

·

Edited

0

1. 현재 학습 진도

  • 몇 챕터/몇 강을 수강 중이신가요?

    • 8.1-5 알고리즘과 친해지기 (2) - 최빈값찾기

  • 어떤 알고리즘을 학습하고 계신가요?

    • 최빈값 찾기

       

2. 어려움을 겪는 부분

  • 어느 부분에서 막히셨나요?

    • 왜 배열로 푸는 것이 제일 낫나요?

    • 저는 java의 map을 사용해서 풀었는데 이건 좋지 않은 풀이법일까요?

       

 

3. 시도해보신 내용

  • 현재 작성하신 코드를 공유해주세요

public class FindMaxOccurredAlphabet0102 {
  public static void main(String[] args) {
    System.out.println("정답 = i 현재 풀이 값 = " + solution("hello my name is dingcodingco"));
    System.out.println("정답 = e 현재 풀이 값 = " + solution("we love algorithm"));
    System.out.println("정답 = b 현재 풀이 값 = " + solution("best of best youtube"));
  }

  public static char solution(String s) {
    Map<Character, Integer> map = new HashMap<>();
    for (int i = 0; i < s.length(); i++) {
      char c = s.charAt(i);
      if (!Character.isLetter(c)) {
        continue;
      }
      map.put(c, map.getOrDefault(c, 0) + 1);
    }
    List<Map.Entry<Character, Integer>> list = new ArrayList<>(map.entrySet());
    list.sort(
        (a, b) -> b.getValue() - a.getValue()
    );
    return list.get(0).getKey();
    }
}
python코딩-테스트알고리즘data-structure지금-베스트

Answer 2

2

dingcodingco님의 프로필 이미지
dingcodingco
Instructor

안녕하세요 지협님! 좋은 질문 감사합니다! 직접 풀어보고 "왜 배열이 더 나을까?"라고 고민하는 과정 자체가 실력을 키우는 데 정말 좋은 습관입니다

1. 왜 배열로 푸는 것이 "제일 낫다"고 하는가?

결론부터 말씀드리면, 이 문제에서 배열이 권장되는 이유는 "알파벳은 a~z까지 딱 26개로 고정"이라는 특성 때문이에요.

alphabet_occurrence_array = [0] * 26 이렇게 길이 26짜리 배열을 만들면, 'a'는 0번 인덱스, 'b'는 1번 인덱스... 이런 식으로 아스키코드 계산(ord(char) - ord('a'))만으로 바로 접근할 수 있어요. 마치 캡슐호텔에서 번호만 알면 바로 방을 찾는 것처럼요.

이 방식의 장점은 크게 세 가지예요.

첫째, 추가적인 자료구조가 필요 없어요. 단순 int 배열 하나면 충분하기 때문에 메모리 오버헤드가 거의 없어요. HashMap은 내부적으로 해시 버킷, Entry 객체, 링크드리스트 등 부가적인 구조를 만들어야 하거든요.

둘째, 접근 속도가 순수 O(1)이에요. 배열의 인덱스 접근은 메모리 주소를 직접 계산해서 바로 가는 거라서, HashMap의 해시 계산 → 버킷 찾기 → 키 비교 과정보다 실제 실행 속도가 빨라요. 빅오 표기법으로는 둘 다 O(1)이지만, 상수 시간의 크기가 다른 거죠.

셋째, "최빈값이 여러 개일 경우 알파벳 순서가 앞인 것을 반환"하라는 조건을 자연스럽게 처리할 수 있어요. 배열은 인덱스 0(a)부터 순서대로 돌기 때문에, 같은 빈도수면 먼저 만난 게 자동으로 알파벳 순 앞쪽이에요. HashMap은 순서를 보장하지 않아서 별도의 정렬 처리가 필요하죠.

정리하면, 이 문제처럼 "저장해야 할 키의 범위가 고정되어 있고, 그 범위가 작을 때"는 배열이 가장 단순하고 효율적인 선택이에요. 강의에서 이 풀이를 가르치는 이유도, 알고리즘 문제에서 이런 "고정 범위 → 배열 매핑" 패턴이 굉장히 자주 나오기 때문이에요.

 

2. Map을 사용한 풀이가 좋지 않은 풀이인가?

전혀 나쁜 풀이가 아니에요! 오히려 실무적으로 보면 HashMap을 쓰는 게 더 자연스러운 경우가 많아요. 코드를 보면 getOrDefault도 잘 활용하고 계시고, 로직도 깔끔해요.

다만 몇 가지 차이점은 알아두면 좋아요.

시간복잡도 측면에서, 지협님의 코드에서 마지막에 list.sort()로 정렬하는 부분이 O(K log K) (K는 등장한 알파벳 수)를 추가로 소요해요. 배열 풀이는 그냥 26개를 순회하면서 최댓값을 찾으니 O(26) = O(1)이고요. 물론 K가 최대 26이라 실질적인 차이는 거의 없지만, 정렬 없이도 풀 수 있다는 점은 알아두시면 좋아요.

만약 Map으로 풀되 정렬 없이 하고 싶다면 이렇게도 가능해요:

public static char solution(String s) {
    Map<Character, Integer> map = new HashMap<>();
    for (int i = 0; i < s.length(); i++) {
        char c = s.charAt(i);
        if (!Character.isLetter(c)) continue;
        map.put(c, map.getOrDefault(c, 0) + 1);
    }

    char maxChar = 'z';
    int maxCount = 0;
    for (Map.Entry<Character, Integer> entry : map.entrySet()) {
        // 빈도가 더 크거나, 같으면 알파벳 순서가 앞인 것을 선택
        if (entry.getValue() > maxCount ||
            (entry.getValue() == maxCount && entry.getKey() < maxChar)) {
            maxCount = entry.getValue();
            maxChar = entry.getKey();
        }
    }
    return maxChar;
}

이러면 정렬 없이 O(N) 한 번에 해결돼요.

3. 그러면 언제 배열을, 언제 Map을 쓰는 게 좋을까?

이 판단 기준을 갖고 가시면 앞으로 비슷한 문제에서 바로 적용할 수 있어요.

배열이 유리한 경우: 키의 범위가 고정되고 작을 때 (알파벳 26개, 숫자 0~9, ASCII 128개 등). 이런 문제를 만나면 "배열로 매핑하면 되겠다!"라고 바로 떠올리시면 돼요.

Map이 유리한 경우: 키의 범위를 예측할 수 없거나 범위가 매우 클 때 (예: 단어별 빈도수 세기, 좌표 매핑 등). 이런 경우는 배열을 잡기 어려우니 Map이 자연스러워요.

지협님이 Map으로 먼저 풀어본 건 정말 좋은 접근이에요. 실제 코딩테스트에서는 Map으로 풀어도 충분히 통과하는 경우가 대부분이거든요. 다만 이 강의에서 배열 풀이를 강조하는 건, "고정 범위 → 배열 매핑"이라는 핵심 패턴을 익히게 하려는 의도예요. 이 패턴을 알아두면 나중에 더 복잡한 문제에서 응용할 수 있거든요.

Java에서 배열로 풀어보고 싶으시다면 이런 식으로 작성할 수 있어요

public static char solution(String s) {
    int[] count = new int[26]; // 알파벳 26개 고정 배열
    for (int i = 0; i < s.length(); i++) {
        char c = s.charAt(i);
        if (!Character.isLetter(c)) continue;
        count[c - 'a']++; // 아스키코드로 인덱스 매핑
    }

    int maxIndex = 0;
    for (int i = 1; i < 26; i++) {
        if (count[i] > count[maxIndex]) {
            maxIndex = i;
        }
    }
    return (char) (maxIndex + 'a');
}

Python의 ord(char) - ord('a')가 Java에서는 c - 'a'로 더 간단하게 표현돼요. Java는 char 타입이 숫자로 바로 연산되니까요.

두 가지 방식 모두 직접 구현해보시면 "아, 이래서 배열이 깔끔하구나"를 체감하실 수 있을 거예요. 이해 안 되는 부분 있으면 언제든 또 질문해주세요!

a939518771님의 프로필 이미지
a939518771
Questioner

상세한 답변 감사드립니다

0

안녕하세요, 인프런 AI 인턴입니다. 김지협님.

질문해주신 내용은 최빈값 찾기에 대한 다양한 접근 방식입니다. Java의 Map을 사용하여 문제를 풀어주셨는데요, 이 방법은 충분히 좋은 방법입니다. 다만 배열과 비교하여 각각의 장점과 단점이 있기에 이를 잘 이해하고 활용하는 것이 중요합니다.

배열과 Map의 차이

  1. 배열:

    • 고정 길이: 배열은 정해진 크기를 가지고 있습니다. 따라서 메모리 사용이 고정적이며, 효율적인 면이 있습니다. 예를 들어, ASCII 알파벳의 경우 크기는 26으로 고정되며, 직관적으로 알파벳의 빈도를 세는 데 용이합니다.
    • 빠른 접근: 인덱스를 통해 빠르게 접근 가능하여, 특정한 경우 더 빠른 성능을 발휘할 수 있습니다.
  2. Map:

    • 유연성: 다양한 자료형의 키를 사용할 수 있고, 크기가 동적이어서 입력 데이터에 따라 유연하게 크기를 조정할 수 있습니다.
    • 가독성: 키-값 쌍을 사용하므로 읽고 이해하기가 쉬울 수 있습니다.

Java 코드 평가

  • 가독성과 직관성: Map을 사용하여 알파벳의 빈도를 계산하고, 정렬하여 최빈 알파벳을 찾는 방식은 가독성이 좋고 이해하기 쉽습니다.
  • 다양한 데이터 처리: 다양한 입력 데이터 형태를 처리할 수 있어 범용성이 높습니다.

하지만 이 코드에서는 사전 순으로 가장 앞에 위치한 알파벳을 반환하지 않고, 값들이 정렬되어 있는 순서에 따라 가장 높은 빈도의 첫 번째 문자를 반환합니다. 동일한 빈도의 알파벳이 있을 때 사전 순으로 먼저 오는 문자를 반환하는 기능이 필요하다면, 조금 더 수정이 필요할 수 있습니다.

참고할 만한 자료

최빈값 찾기에 대해 다양한 방법을 다룬 기존 답변을 참고하시면 좋습니다:

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

a939518771's profile image
a939518771

asked

Ask a question