코딩테스트 Map 풀이: 학급 회장 득표수 세기

··설명 약 7분·작성: 해비·블로그 소개

읽기 전에 알아두면 좋아요

아래 개념이 익숙하면 본문을 바로 읽으세요. 낯선 개념만 링크에서 복습하면 됩니다.

개념과 예제는 실행하지 않아도 읽을 수 있습니다. 내 컴퓨터·터미널에서 직접 실행하는 과정은 선택 실습입니다.

과정 위치와 선택 복습 안내

과정 위치: 자료구조 개념과 문제 · 문제

과정 위치는 이 글이 속한 묶음입니다. 이 단계의 모든 개념을 먼저 읽을 필요는 없습니다. 위에 연결한 개념 중 낯선 내용만 복습하세요. 문제의 조건·상태·갱신 순서는 익숙한 언어로 설명하면 됩니다.

JavaScript로 문법·실행 복습하기 (선택)

개념 글의 코드는 JavaScript 예시입니다. 문제 화면에서는 JavaScript·Python·Java·C++·C# 중 익숙한 언어의 함수를 작성하세요. 본문의 Node.js 입출력 예시는 로컬 실행을 위한 별도 안내입니다.

학급 회장 문제에서는 후보별 투표가 담긴 문자열로 누구를 찾나요?

후보별 투표가 담긴 문자열에서 가장 많은 표를 받은 후보를 찾는 문제입니다. 문자열·반복문·빈도의 기본을 준비하고, 아래 입력·반환 계약을 확인해 직접 풀어보세요.

적용 조건·범위: 반드시 한 명의 학급 회장만 선출되는 투표 결과만 주어진다고 가정합니다.

본문 근거: MDN Map 문서

문제 설명

코딩테스트 JS Map 풀이: 학급 회장 득표수 세기 전반부 흐름 정리

학급 회장을 뽑기 위해 후보 기호 A, B, C, D, E가 등록되어 있습니다.

투표용지에는 반 학생들이 자기가 선택한 후보의 기호(알파벳)를 하나씩 작성하며,
선생님은 이 기호들을 순서대로 발표합니다.

선생님의 발표가 모두 끝난 후,
어떤 기호의 후보가 학급 회장이 되었는지를 출력하는 프로그램을 작성하세요.

반드시 한 명의 학급 회장만 선출되는 투표 결과만 주어진다고 가정합니다.

입력 설명

첫 번째 줄에는 반 학생 수 N이 주어집니다. (5 ≤ N ≤ 50)

두 번째 줄에는 N개의 투표용지에 쓰여 있던 각 후보의 기호가
선생님이 발표한 순서대로 문자열로 주어집니다.

출력 설명

학급 회장으로 선택된 후보의 기호를 출력합니다.


입력 예제
15
BACBACCACCBDEDE

출력 예제
C

직접 풀어보기

먼저 선택한 언어의 입력·반환 계약에 맞춰 작성해 보세요. 힌트 받기와 정답과 비교하기는 코드를 실행하지 않는 AI 분석입니다. 해답·해설은 아래에서 필요할 때 펼칠 수 있습니다.

0 / 6,000바이트

solution(s)에 s(문자열)를 전달하고 문자열를 반환합니다. 아래 문제의 유효 입력 조건을 따릅니다. 표준 입력과 출력 코드는 작성하지 않습니다. Tab은 다음 항목으로 이동합니다. 입력 영역 오른쪽 아래를 끌어 높이를 조절할 수 있습니다.

비밀키·개인정보는 입력하지 마세요. 코드는 이 페이지에만 유지됩니다.

해답·해설 보기
JavaScript 해답
function solution(s) {
    const counts = new Map();
    for (const ch of s) counts.set(ch,(counts.get(ch) || 0) + 1);
    let best = "", max = 0;
    for (const[ch, count] of counts) {
        if (count > max) {
            best = ch;
            max = count;
        }
    }
    return best;
}

solution(s)에 s(문자열)를 전달하고 문자열를 반환합니다. 아래 문제의 유효 입력 조건을 따릅니다. 표준 입력과 출력 코드는 작성하지 않습니다.

내가 푼 풀이

function solution(s) {
  let arr = s.split("");

  let obj = arr.reduce((acc, cur) => {
    acc[cur] += 1;
    return acc;
  }, { A: 0, B: 0, C: 0, D: 0, E: 0 });

  let maxKey = null;
  let maxValue = -Infinity;

  for (const key in obj) {
    if (obj[key] > maxValue) {
      maxValue = obj[key];
      maxKey = key;
    }
  }

  return maxKey;
}

이 풀이는 후보가 A~E로 고정되어 있다는 문제 조건을 코드에 직접 반영한 방식입니다. 객체를 미리 초기화해 두고, 문자열을 순회하며 각 후보의 득표 수를 누적합니다.

동작 메커니즘은 단순합니다. 문자열을 배열로 변환한 뒤, reduce를 이용해 각 문자에 해당하는 카운트를 증가시키고, 이후 한 번의 반복으로 최댓값을 가진 키를 찾습니다.

실수하기 쉬운 포인트는 초기 객체에 없는 문자가 등장할 가능성을 고려하지 않았다는 점입니다. 현재 문제에서는 조건상 문제가 없지만, 입력 조건이 조금만 바뀌면 런타임 오류 또는 잘못된 결과로 이어질 수 있습니다.

개선 방향으로는 초기 객체를 하드코딩하지 않고, 등장하는 값만 동적으로 집계하도록 구조를 바꾸는 것이 좋습니다.

정답 풀이

코딩테스트 JS Map 풀이: 학급 회장 득표수 세기 후반부 흐름 정리
function solution(s) {
  let answer;
  let sH = new Map();

  for (let x of s) {
    if (sH.has(x)) sH.set(x, sH.get(x) + 1);
    else sH.set(x, 1);
  }

  let max = Number.MIN_SAFE_INTEGER;
  for (let [key, val] of sH) {
    if (val > max) {
      max = val;
      answer = key;
    }
  }

  return answer;
}

정답 풀이는 후보의 종류를 사전에 가정하지 않습니다. 문자열을 순회하면서 실제로 등장한 문자만 Map에 저장하고, 그 빈도를 누적합니다.

이 방식의 핵심은 확장성입니다. 후보가 늘어나거나 문자 종류가 변경되더라도 코드 수정 없이 그대로 동작합니다.

일반적인 JavaScript 구현에서는 각 Map 접근을 평균 상수 시간으로 보고 전체를 O(N)으로 설명합니다. 다만 명세가 특정 해시 테이블 구현이나 모든 접근의 정확한 O(1)을 보장하는 것은 아닙니다.

출제 의도

이 문제는 단순 구현 문제가 아니라, 문자열 데이터를 집계할 때 어떤 자료구조를 선택해야 하는지를 묻는 문제입니다.

이 글에서는 해시(Map)를 이용한 빈도 집계 패턴을 연습합니다. 출제자가 특정 자료구조만 요구했다고 단정하지 않고 입력 조건과 출력 결과로 풀이를 판단합니다.

문제의 입력 조건과 시간·메모리 제한을 만족한다면 초기화된 객체를 쓰는 풀이도 정답입니다. 여기서는 다른 문제로 확장하기 쉬운 빈도 집계 패턴을 익히기 위해 Map 풀이를 함께 제시합니다.

이 문제는 이후 등장하는 해시 문제들의 기초 사고를 형성하기 위한 전형적인 입문 문제로 볼 수 있습니다.

빈도 비교 문제를 한 단계 확장하려면 JS 아나그램 슬라이딩 윈도우를 함께 읽으면 흐름이 연결됩니다.

Map 동작·동률·검증 기준

득표 문자열 길이를 N, 서로 다른 후보 수를 U라고 하면 Map 풀이의 추가 공간은 빈도표 O(U), 반환 후보 하나는 O(1)입니다. 이 문제는 후보가 A~E로 고정되어 U≤5이므로 계산용 추가 공간은 O(1)로 볼 수 있습니다. 이미 전달된 입력 문자열까지 포함하면 O(N+U) 저장 공간입니다. 앞의 객체 비교 풀이는 split("")로 문자 배열도 만들기 때문에 그 배열에 O(N) 추가 공간을 사용합니다.

Map은 키와 값을 저장하고 키가 처음 삽입된 순서를 기억합니다. 따라서 현재 정답 코드는 동률이면 투표 문자열에서 먼저 처음 등장해 Map에 삽입된 후보를 반환합니다. 문제가 유일한 최다 득표자를 보장하지 않는다면 사전순, 공동 우승자 배열, 재투표 같은 동률 규칙을 별도로 정해야 합니다.

JavaScript 명세는 Map 접근 시간이 원소 수에 대해 평균적으로 선형보다 빨라야 한다고 요구하지만, 내부 구현이 반드시 해시 테이블이거나 모든 연산이 정확히 O(1)이라고 보장하지는 않습니다. 코딩 테스트에서는 일반적인 구현을 전제로 전체 순회를 O(N)으로 설명하되, 이 구분은 MDN Map 문서와 함께 적는 편이 정확합니다.

console.assert(solution('BACBACCACCBDEDE') === 'C');
console.assert(solution('AB') === 'A'); // 현재 구현의 동률 규칙: 먼저 삽입된 후보
console.assert(solution('') === undefined); // 빈 입력 정책을 호출부에서 결정

빈 문자열에서는 answer가 정해지지 않아 undefined를 반환합니다. 문제 입력이 최소 한 표를 보장하면 괜찮지만, 범용 함수라면 빈 입력에서 오류를 낼지, null을 반환할지 명시하세요.

A~E만 나온다는 현재 조건에서는 초기값을 가진 일반 객체 풀이도 정확합니다. 후보가 동적으로 늘어나면 Map은 별도 초기화 없이 키를 추가할 수 있고, 문자열뿐 아니라 다른 타입도 키로 사용할 수 있다는 장점이 있습니다. 객체로 일반화한다면 상속된 프로퍼티와 사용자 입력 키가 충돌하지 않도록 Object.create(null) 또는 소유 프로퍼티 검사도 고려해야 합니다.

입력 검증 역시 자료구조 선택과 별개입니다. 허용되지 않은 기호를 무시할지 오류로 처리할지, 대소문자를 같은 후보로 볼지, 공백을 투표로 셀지를 정하지 않으면 같은 함수가 호출 위치마다 다른 의미로 사용될 수 있습니다.

정리: 빈도 집계는 ‘키가 늘어나도 코드가 바뀌지 않는가’뿐 아니라 빈 입력과 동률을 어떻게 처리하는지까지 정해야 완성됩니다. 이 세 조건을 테스트에 고정하면 후보 종류가 바뀌어도 안전하게 재사용할 수 있습니다. 특히 동률 규칙은 구현의 우연한 순서에 맡기지 말고 요구사항 이름으로 테스트에 남기세요.

QnA

Q. 내가 푼 풀이는 틀린 답인가요?
아닙니다. 현재 문제 조건에서는 완전히 올바른 답입니다. 다만 조건이 바뀌면 바로 수정이 필요하다는 한계가 있습니다.

Q. 왜 Map 풀이가 정답으로 제시되나요?
후보의 종류가 달라지거나 늘어나더라도 그대로 사용할 수 있는 범용적인 해시 패턴이기 때문입니다.

Q. 실전 코딩테스트에서는 어떤 풀이가 안전한가요?
현재처럼 후보가 A~E로 고정되면 초기화 객체와 Map 모두 사용할 수 있습니다. 후보 종류가 달라지면 집계 키를 만드는 방식과 허용 입력·동률 규칙을 함께 정해야 하며, Map을 썼다는 이유만으로 입력 검증이 끝나지는 않습니다.

이 문제를 푼 뒤 확인하기

유일한 최다 득표자 조건을 확인하고, 후보 한 명에 투표가 몰린 경우 빈도표를 직접 만들어 보세요.

본문의 예제와 이 반례를 직접 실행해 예상 출력과 비교하고, 결과가 다르면 입력 조건과 반복 범위를 다시 확인하세요.

풀이 함수를 독립 실행해 확인합니다

선수 지식은 배열·조건문·반복문과 위에서 설명한 자료구조입니다. 정답 풀이의 완성 함수 블록 하나를 solution.cjs로 저장하고, 그 아래에 다음 호출을 붙입니다. 앞의 비교용 풀이와 같은 이름의 함수를 함께 붙이지 않습니다. 터미널에서 node solution.cjs로 실행합니다.

console.log(JSON.stringify(solution(...["AAAAA"])));

이 변형 호출의 JSON 출력은 "A"입니다. 기존 함수 블록의 console.log가 있으면 그 출력 다음 줄에서 확인합니다.

글 소개·학습 준비·전체 목차

주요 포인트 한눈에 보기

각 후보 기호의 등장 횟수를 세고 가장 많은 표를 받은 후보를 선택합니다. 고정 후보 A~E를 초기화한 객체와 Map 풀이를 비교하고, 유일한 승자 조건·빈 입력·동률에서 구현이 어떻게 동작하는지 구분합니다.

이 글이 도움이 되었나요?

조회 중

이어서 공부하기

체크포인트: 해설을 가리고 다시 풀고, 경계 입력을 하나 바꾸어 예상 결과와 실제 결과를 비교하세요. 삽입·제거 전후의 상태를 그리고, 내장 도구를 쓰는 풀이와 직접 구현의 목적을 구분하세요.

다음 추천 · 자료구조 개념: JavaScript 문자열 해시 테이블 구현: 충돌 처리와 리사이즈, NFC 정규화

같은 주제에서 다음 개념과 예제로 이해를 넓힙니다.

권장 순서는 학습 가이드와 같습니다. 다른 순서는 접힌 참고 목록에서 확인할 수 있습니다. 읽음 표시는 숙달이나 채점 결과가 아닙니다.

원래 과정 목록 순서 (선택)

읽음 기록

읽음 — / 전체 58개 · 필수 58개

이 글을 쓴 해비

웹사이트를 제작·운영하고, 개인 서비스와 자동화·AI 도구를 만듭니다. 직접 만들며 배운 내용과 문제 해결 과정을 BlogFlow에 기록합니다.

새 글 받아보기

RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.

RSS 피드 구독하기

댓글 남기기