https://school.programmers.co.kr/learn/courses/30/lessons/138476
프로그래머스
SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
문제 설명
경화는 과수원에서 귤을 수확했습니다. 경화는 수확한 귤 중 '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
입출력 예
입출력 예 설명
입출력 예 #1
본문에서 설명한 예시입니다.
입출력 예 #2
경화는 크기가 2인 귤 2개와 3인 귤 2개 또는 2인 귤 2개와 5인 귤 2개 또는 3인 귤 2개와 5인 귤 2개로 귤을 판매할 수 있습니다. 이때의 크기 종류는 2가지로 이 값이 최소가 됩니다.
입출력 예 #3
경화는 크기가 1인 귤 2개를 판매하거나 2인 귤 2개를 판매할 수 있습니다. 이때의 크기 종류는 1가지로, 이 값이 최소가 됩니다.
풀이
접근 방식
귤의 크기별로 개수를 저장하고 (HashMap 사용)
개수를 내림차순 정렬하여 (ArrayList 사용)
개수가 큰 값부터 k에서 차감하면서, 차감되는 횟수(int형 변수 answer)를 ++하고
k가 0보다 작거나 같아지면 차감 횟수를 반환하도록 했다.
HashMap 활용
put(K key, V value)
- 기능 : HashMap에 키와 값의 쌍을 저장
- 동작 :
- 주어진 키가 존재하지 않으면 새로 추가
- 키가 이미 존재하면, 해당 키의 기존 값을 새로운 값으로 덮어씀
- 반환 : 키가 이미 존재했다면 기존 값을 반환, 존재하지 않았다면 null 반환
get(Object key)
- 기능 : 주어진 키에 매핑된 값을 반환
- 동작 :
- 키가 존재하면 해당 값을 반환
- 키가 존재하지 않으면 null 반환
- 반환 : 키에 매핑된 값 또는 null
getOrDefault(Object key, V defaultValue)
- 기능 : 주어진 키에 매핑된 값을 반환하되, 키가 존재하지 않으면 기본값을 반환
- 동작 :
- 키가 존재하면 해당 값을 반환
- 키가 존재하지 않으면 기본값을 반환
- 반환 : 키에 매핑된 값 또는 기본값(defaultValue)
활용
HashMap<Integer, Integer> sizeCount = new HashMap<>();
for (int size : tangerine) {
sizeCount.put(size, sizeCount.getOrDefault(size, 0) + 1);
}
- sizeCount를 정의한다.
- key값은 귤의 크기(size)
- value는 key크기에 해당하는 귤의 개수(count)
- put 메서드로 size와 count를 저장한다.
- size가 이미 저장된 키값이면, 새로 넣은 value값으로 갱신된다.
- getOrDefault 메서드로 size가 저장된 값이라면 그 값을 불러온 다음 +1을 해서 저장하고,
처음 저장되는 값이라면 default값인 0에 +1을 해서 저장한다.
➡️ 귤의 크기(size)를 key값으로 가지고 귤의 개수(count)를 value로 가지는 HashMap 완성❗
ArrayList 정렬 후 반환 중 발생한 오류 : stream toList(), ImmutableCollections
ArrayList<Integer> sortedCount = new ArrayList<>(sizeCount.values());
sortedCount = (ArrayList<Integer>) sortedCount.stream()
.sorted(Comparator.reverseOrder())
.toList();
Exception in thread "main" java.lang.ClassCastException: class java.util.ImmutableCollections$ListN cannot be cast to class java.util.ArrayList (java.util.ImmutableCollections$ListN and java.util.ArrayList are in module java.base of loader 'bootstrap')
stream의 sorted로 ArrayList를 정렬하고 이 결과를 toList()를 이용해 반환 받으니, 런타임 오류가 발생했다.
찾아보니 toList로 반환된 리스트는 ImmutableCollections 클래스, 불변 컬렉션이라서 수정이 불가능하다는 것이었다.
✏️ ImmutableCollections
Java 9에서 추가된 불변 컬렉션.
수정이 불가능한 컬렉션 객체를 제공하며, 이를 통해 데이터의 안전성과 성능 최적화를 지원하는 클래스.
✏️ 불변 컬렉션
불변 컬렉션은 생성 이후 추가, 삭제, 수정이 불가능한 컬렉션이다. (읽기 전용)
Java 9부터 제공되는 List.of(), Set.of(), Map.of() 메서드는 ImmutableCollections를 반환한다.
즉, 해당 오류는 .toList()가 반환하는 불변 리스트를 ArrayList로 캐스팅하려고 해서 발생했다.
해결 방법
1) collect(Collectors.toList()) 활용
toList()를 collect(Collectors.toList())로 대체하면 하면 List로 반환되어 ArrayList로 캐스팅해도 오류가 발생하지 않았다.
그런데 이 방식으로 수정하면 IntelliJ에서 해당 라인에 노란색 밑줄을 긋고 toList()로 변경할 수 있는 안내가 뜬다..
((그렇게 바꾸면 오류 난다고...🥲))
이게 보기 싫었기 때문에 다른 방식을 찾아보았다.
2) 불변리스트 활용
List<Integer> sortedCount = sizeCount.values()
.stream()
.sorted(Comparator.reverseOrder())
.toList();
toList()로 반환되는 객체를 확인해보면 List<T>임을 확인할 수 있다.
따라서, 반환 받는 값을 List로 지정하면 오류 없이 받을 수 있다.
나는 이후 코드에서 sortedCount를 수정할 일이 없기 때문에 불변리스트로써 sortedCount를 사용해도 문제가 없었다.
풀이 코드
import java.io.*;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) throws IOException {
int k = 6;
int[] tangerine = new int[]{1, 3, 2, 5, 4, 5, 2, 3};
int answer = 0;
HashMap<Integer, Integer> sizeCount = new HashMap<>();
for (int size : tangerine) {
sizeCount.put(size, sizeCount.getOrDefault(size, 0) + 1);
}
//ArrayList<Integer> sortedCount = new ArrayList<>(sizeCount.values());
/* toList() : 오류 발생*/
/*sortedCount = (ArrayList<Integer>) sortedCount.stream()
.sorted(Comparator.reverseOrder())
.toList();*/
/*sortedCount = (ArrayList<Integer>) sortedCount.stream()
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList());*/
List<Integer> sortedCount = sizeCount.values()
.stream()
.sorted(Comparator.reverseOrder())
.toList();
for (int cnt : sortedCount) {
k -= cnt;
answer ++;
if (k <= 0) break;
}
System.out.println(answer);
}
}
제출
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.stream.Collectors;
class Solution {
public int solution(int k, int[] tangerine) {
int answer = 0;
HashMap<Integer, Integer> sizeCount = new HashMap<>();
for (int size : tangerine) {
sizeCount.put(size, sizeCount.getOrDefault(size, 0) + 1);
}
ArrayList<Integer> sortedCount = new ArrayList<>(sizeCount.values());
sortedCount = (ArrayList<Integer>) sortedCount.stream()
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList());
for (int cnt : sortedCount) {
k -= cnt;
answer ++;
if (k <= 0) break;
}
return answer;
}
}
'Algorithm Solving > Java' 카테고리의 다른 글
[programmers] Java Lv.2 - 연속 부분 수열 합의 개수 (0) | 2025.01.13 |
---|---|
[programmers] Java Lv.2 - 괄호 회전하기 (0) | 2025.01.10 |
[programmers] Java Lv.2 - 멀리 뛰기 (0) | 2025.01.08 |
[programmers] Java Lv.2 - N개의 최소공배수 (1) | 2025.01.07 |
[programmers] Java Lv.2 - 예상 대진표 (0) | 2025.01.06 |