TIL(63)

이채원·2026년 9월 18일

TIL

목록 보기
65/73

오늘의 할일
1. 코드카타 정리
2. 팀프로젝트 정리
3. 다음 학습 목표

개념 요약


코드카타 정리

과일 장수가 사과 상자를 포장하고 있습니다. 사과는 상태에 따라 1점부터 k점까지의 점수로 분류하며, k점이 최상품의 사과이고 1점이 최하품의 사과입니다. 사과 한 상자의 가격은 다음과 같이 결정됩니다.

한 상자에 사과를 m개씩 담아 포장합니다.
상자에 담긴 사과 중 가장 낮은 점수가 p (1 ≤ p ≤ k)점인 경우, 사과 한 상자의 가격은 p * m 입니다.
과일 장수가 가능한 많은 사과를 팔았을 때, 얻을 수 있는 최대 이익을 계산하고자 합니다.(사과는 상자 단위로만 판매하며, 남는 사과는 버립니다)

예를 들어, k = 3, m = 4, 사과 7개의 점수가 [1, 2, 3, 1, 2, 3, 1]이라면, 다음과 같이 [2, 3, 2, 3]으로 구성된 사과 상자 1개를 만들어 판매하여 최대 이익을 얻을 수 있습니다.

(최저 사과 점수) x (한 상자에 담긴 사과 개수) x (상자의 개수) = 2 x 4 x 1 = 8
사과의 최대 점수 k, 한 상자에 들어가는 사과의 수 m, 사과들의 점수 score가 주어졌을 때, 과일 장수가 얻을 수 있는 최대 이익을 return하는 solution 함수를 완성해주세요.

#include <string>
#include <vector>
#include <algorithm>

using namespace std;

int solution(int k, int m, vector<int> score) {
    int answer = 0;

    // 사과 점수 오름차순 정렬
    sort(score.begin(), score.end());

    int count = 0; // 상자에 담은 사과 개수를 셀 변수

    // 가장 비싼 사과(배열의 맨 뒤)부터 하나씩 
    for (int i = score.size() - 1; i >= 0; i--) {
        count++; // 사과 하나 담기

        // 상자에 사과가 m개 -> 포장해서 팔기
        if (count == m) {
            // 제일 비싼 것부터 먼저 담았으므로, m번째로 담긴 지금 사과(score[i])가 
            // 이 상자 안에서는 가장 점수가 낮은 사과
            int lowest_score = score[i];
            
            // 최저 점수 * 사과 개수
            answer += lowest_score * m; 

            count = 0; 
        }
    }

    return answer;
}

AI가 작성한 코드

#include <vector>
#include <algorithm> // sort, greater 함수 사용

using namespace std;

int solution(int k, int m, vector<int> score) {
    int answer = 0;

    // 1. 오름차순 대신 내림차순(큰 점수 -> 작은 점수)으로 배열을 정렬합니다.
    sort(score.begin(), score.end(), greater<int>());

    // 2. 사과를 하나씩 세지 않고, m개씩 뭉텅이로 건너뛰며(i += m) 계산합니다.
    for (int i = m - 1; i < score.size(); i += m) {
        // 내림차순 정렬되어 있으므로, m개씩 끊었을 때 마지막 사과(score[i])가 무조건 최저 점수입니다.
        answer += score[i] * m;
    }

    return answer;
}

greater<int>()를 이용한 내림차순 정렬:
greater<int>()를 sort에 추가해주면 배열이 애초에 "가장 비싼 사과부터 싼 사과 순서"로 세팅. 사람이 생각하는 "좋은 것부터 담는다"는 흐름과 데이터의 방향이 100% 일치

루프 건너뛰기 (i += m):
i += m을 사용하면 굳이 1, 2, 3번째 사과를 세지 않고 목표물로 바로바로 점프합니다. 반복 횟수가 NN번에서 N/mN / m번으로 줄어듭니다.

.
.
.
.
수포자는 수학을 포기한 사람의 준말입니다. 수포자 삼인방은 모의고사에 수학 문제를 전부 찍으려 합니다. 수포자는 1번 문제부터 마지막 문제까지 다음과 같이 찍습니다.

1번 수포자가 찍는 방식: 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...
2번 수포자가 찍는 방식: 2, 1, 2, 3, 2, 4, 2, 5, 2, 1, 2, 3, 2, 4, 2, 5, ...
3번 수포자가 찍는 방식: 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, ...

1번 문제부터 마지막 문제까지의 정답이 순서대로 들은 배열 answers가 주어졌을 때, 가장 많은 문제를 맞힌 사람이 누구인지 배열에 담아 return 하도록 solution 함수를 작성해주세요.

제한 조건
시험은 최대 10,000 문제로 구성되어있습니다.
문제의 정답은 1, 2, 3, 4, 5중 하나입니다.
가장 높은 점수를 받은 사람이 여럿일 경우, return하는 값을 오름차순 정렬해주세요.

#include <string>
#include <vector>
#include <algorithm> // max 함수 사용

using namespace std;

vector<int> solution(vector<int> answers) {
    vector<int> answer;
    
    // 수포자 3인방이 찍는 패턴 배열
    vector<int> math_hater_1 = {1, 2, 3, 4, 5}; // 5개씩 반복
    vector<int> math_hater_2 = {2, 1, 2, 3, 2, 4, 2, 5}; // 8개씩 반복
    vector<int> math_hater_3 = {3, 3, 1, 1, 2, 2, 4, 4, 5, 5}; // 10개씩 반복
    
    // 점수를 기록할 변수
    int score1 = 0;
    int score2 = 0;
    int score3 = 0;
    
    // answers를 1번 문제부터 끝까지 하나씩
    for (int i = 0; i < answers.size(); i++) {
        // i번 문제 정답이랑 수포자가 찍은 번호가 같으면 점수 1점
        // %를 쓰면 패턴의 길이만큼 알아서 돔
        if (answers[i] == math_hater_1[i % 5]) {
            score1++;
        }
        if (answers[i] == math_hater_2[i % 8]) {
            score2++;
        }
        if (answers[i] == math_hater_3[i % 10]) {
            score3++;
        }
    }
    
    // 세 사람 중 가장 높은 점수가 몇 점인지
    int max_score = max(score1, max(score2, score3));
    
    // 최고점과 점수가 같은 사람 순서 push_back
    if (score1 == max_score) answer.push_back(1);
    if (score2 == max_score) answer.push_back(2);
    if (score3 == max_score) answer.push_back(3);
    
    return answer;
}

AI가 작성한 코드

#include <vector>
#include <algorithm> // max_element 사용

using namespace std;

vector<int> solution(vector<int> answers) {
    // 1. vector 대신 가벼운 C스타일 정적 배열과 constexpr을 사용하여 메모리 할당을 차단합니다.
    constexpr int p1[] = {1, 2, 3, 4, 5};
    constexpr int p2[] = {2, 1, 2, 3, 2, 4, 2, 5};
    constexpr int p3[] = {3, 3, 1, 1, 2, 2, 4, 4, 5, 5};
    
    // 2. 점수를 따로 변수(score1, score2...)로 두지 않고 하나의 배열로 묶어 관리합니다.
    int scores[3] = {0, 0, 0};

    // 3. 정답을 훑으며 각 수포자의 배열 길이로 나눈 나머지(%)를 이용해 점수를 올립니다.
    for (int i = 0; i < answers.size(); i++) {
        if (answers[i] == p1[i % 5])  scores[0]++;
        if (answers[i] == p2[i % 8])  scores[1]++;
        if (answers[i] == p3[i % 10]) scores[2]++;
    }

    // 4. max(A, max(B, C)) 같은 하드코딩 대신, STL 함수를 써서 배열 내 최댓값을 한 번에 뽑아냅니다.
    int max_score = *max_element(scores, scores + 3);

    vector<int> answer;
    answer.reserve(3); // 정답자는 최대 3명이므로 미리 자리를 예약(reserve)해둡니다.

    // 5. 중복되는 if문들을 for문 하나로 압축하여 정답자를 추출합니다.
    for (int i = 0; i < 3; i++) {
        if (scores[i] == max_score) {
            answer.push_back(i + 1); // 사람 번호는 1번부터 시작하므로 인덱스(i)에 1을 더합니다.
        }
    }

    return answer;
}
  1. 메모리 할당(동적 할당) 차단 (constexpr int[])
    constexpr 키워드와 [] 배열을 사용하면, 데이터가 프로그램(실행 파일) 자체에 아예 각인(Hardcoded)되어 서버에 아무리 많은 요청이 들어와도 메모리 생성/삭제 비용이 '0'이 됩니다.
  2. 변수 그룹화로 하드코딩 제거 (DRY 원칙)
    점수를 scores[3]이라는 하나의 배열로 묶고 마지막에 for문으로 돌려주면, 인원이 몇 명으로 늘어나든 코드 길이는 변하지 않는 뛰어난 확장성을 가집니다. (Don't Repeat Yourself 원칙)
  3. *max_element의 우아함
    max_element(시작 주소, 끝 주소)를 사용하면 배열 안에서 가장 큰 값이 있는 곳을 한 번에 찾아줍니다. 앞에 붙은 *는 "그 주소에 있는 알맹이(값)를 꺼내라"는 뜻의 포인터 연산자입니다.

팀프로젝트 정리


다음 학습 목표

profile
초보 개발자

0개의 댓글