[오늘의 문제] 귤 고르기

shlim55·2025년 4월 22일

코딩테스트

목록 보기
33/223

출처: https://school.programmers.co.kr/learn/courses/30/lessons/138476

경화는 과수원에서 귤을 수확했습니다. 경화는 수확한 귤 중 'k'개를 골라 상자 하나에 담아 판매하려고 합니다. 그런데 수확한 귤의 크기가 일정하지 않아 보기에 좋지 않다고 생각한 경화는 귤을 크기별로 분류했을 때 서로 다른 종류의 수를 최소화하고 싶습니다.

예를 들어, 경화가 수확한 귤 8개의 크기가 [1, 3, 2, 5, 4, 5, 2, 3] 이라고 합시다. 경화가 귤 6개를 판매하고 싶다면, 크기가 1, 4인 귤을 제외한 여섯 개의 귤을 상자에 담으면, 귤의 크기의 종류가 2, 3, 5로 총 3가지가 되며 이때가 서로 다른 종류가 최소일 때입니다.

경화가 한 상자에 담으려는 귤의 개수 k와 귤의 크기를 담은 배열 tangerine이 매개변수로 주어집니다. 경화가 귤 k개를 고를 때 크기가 서로 다른 종류의 수의 최솟값을 return 하도록 solution 함수를 작성해주세요.

제한사항
1 ≤ k ≤ tangerine의 길이 ≤ 100,000
1 ≤ tangerine의 원소 ≤ 10,000,000
입출력 예
k tangerine result
6 [1, 3, 2, 5, 4, 5, 2, 3] 3
4 [1, 3, 2, 5, 4, 5, 2, 3] 2
2 [1, 1, 1, 1, 2, 2, 2, 3] 1
입출력 예 설명
입출력 예 #1

본문에서 설명한 예시입니다.
입출력 예 #2

경화는 크기가 2인 귤 2개와 3인 귤 2개 또는 2인 귤 2개와 5인 귤 2개 또는 3인 귤 2개와 5인 귤 2개로 귤을 판매할 수 있습니다. 이때의 크기 종류는 2가지로 이 값이 최소가 됩니다.
입출력 예 #3

경화는 크기가 1인 귤 2개를 판매하거나 2인 귤 2개를 판매할 수 있습니다. 이때의 크기 종류는 1가지로, 이 값이 최소가 됩니다.

내가 30분이내로 작성한 코드다.
문제에대한 이해는 됐는데

뭔가 시간을 더 투자 했으면 풀수 있었으면 하는 맘도 들긴하다.

최솟값을 어떻게 비교해서 반환 해낼까? 그게 잘 안되었던거 같다.

import java.util.*;

class Solution {
public int solution(int k, int[] tangerine) {
int answer = 0;
// 수확한 귤 중 'k'개를 골라 상자 하나에 담아 판매하려고 합니다.
// 귤의 개수 k와 귤의 크기를 담은 배열 tangerine이 매개변수로 주어집니다
// 귤의 크기의 종류 반환 (최솟값)
// case 1
// 1, 4 제외한 나머지 6개뽑을시 -> 2반환
// case 2
// 3, 5 2개씩 뽑을시 -> 2 반환
// 2, 3 2개씩 뽑을시 -> 2 반환
// 2, 5 2개씩 뽑을시 -> 2 반환
// case 3
// 1 2개, 2 2개 뽑을시 -> 1반환

    int arr[] = new int[k];// k크기만큼의 배열 사이즈     
    int min = 100000;// 원소 종류 세기 
    int count = 0; 
    // tangerine 배열에서 뽑는다
    while(true){// 최솟값이 나올때 break       
        for(int i = 0; i < k; i++){//k갯수만큼 랜덤으로 뽑아서(중복가능) arr 배열에 저장
            Random rand = new Random();
            int randomIdx = rand.nextInt(tangerine.length);
            arr[i] = tangerine[randomIdx];
        }    
        // arr[i] 중복 판별
        Set<Integer> numSet = new HashSet<>();
        
        // 저장 시키기 향상 for문
        for(int num : numSet){
            numSet.add(num);
        }
        min = numSet.size();
        Math.min(count, min);
    }
        
    return min;
}

}
지금 작성한 방식은 랜덤하게 k개를 뽑아서 종류 수를 구하는 무작위 시뮬레이션 방식인데, 이건 문제의 의도와는 맞지 않은거 같다.

  1. 귤 크기별 개수를 센다.

  2. 많이 나오는 크기부터 선택한다.

  3. 총 k개가 될 때까지 종류를 늘려가며 고른다.

  4. 이때 사용된 크기 종류 수가 정답!

이렇게 되어야 함.

위 요구 사항을 반영한 코드문이다.
import java.util.*;

class Solution {
public int solution(int k, int[] tangerine) {
Map<Integer, Integer> countMap = new HashMap<>();

    // 1. 귤 크기별 개수 세기
    for (int size : tangerine) {
        countMap.put(size, countMap.getOrDefault(size, 0) + 1);
    }

    // 2. 크기별 개수를 큰 순서로 정렬
    List<Integer> counts = new ArrayList<>(countMap.values());
    counts.sort(Collections.reverseOrder());

    // 3. 많이 나오는 크기부터 고르기
    int answer = 0;
    int total = 0;

    for (int cnt : counts) {
        total += cnt;
        answer++;
        if (total >= k) break;
    }

    return answer;
}

}
맵을 활용하여 크기별 개수를 세고,
개수 큰 순서대로 정렬했다.

맨 마지막 반복문은
정렬된 counts 리스트(= 귤 크기별 개수)를 많이 나온 순서대로 하나씩 보면서,

얼마나 많은 귤을 골랐는지 누적하고 (total += cnt)

몇 가지 크기를 사용했는지 센다. (answer++)

k개 이상을 고르면 종료합니다.

그외에.. 다른분들 풀이

import java.util.*;

class Solution {
public int solution(int k, int[] tangerine) {
int answer = 0;
int[] arr = new int[10000001];
for(int i = 0; i < tangerine.length; i++) {
int num = ++arr[tangerine[i]];
}
Arrays.sort(arr);

    int sum = 0;
    for(int i = arr.length-1; i >= 0; i--) {
        sum += arr[i];
        answer++;
        if(sum >= k) break;
    }

    
    return answer;
}

}

profile
A Normal Programmer

0개의 댓글