-
[프로그래머스] 이모티콘 할인행사코딩 테스트 2025. 3. 24. 21:49
https://school.programmers.co.kr/learn/courses/30/lessons/150368
쌩구현 문제였다.
[풀이한 코드]
import java.util.*; class Solution { static final Map<Integer, Integer> percentMap = Map.of(10, 9, 20, 8, 30, 7, 40, 6); static final int[] pers = new int[]{10, 20, 30, 40}; static int[][] users; static int[] emoticons; static int maxPlusUser; static long maxSale; public int[] solution(int[][] users, int[] emoticons) { this.users = users; this.emoticons = emoticons; int[] percents = new int[emoticons.length]; makePercents(0, percents); return new int[]{maxPlusUser, (int) maxSale}; } private void makePercents(int cnt, int[] percents) { if (cnt == emoticons.length) { event(percents); return; } for (int i = 0; i < 4; i++) { percents[cnt] = pers[i]; makePercents(cnt + 1, percents); } } private void event(int[] percents) { // 이모티콘 구매자 List<Integer>[] emoticonBuyers = makeEmoticonBuyers(percents); // 할인된 이모티콘 가격 int[] emoticonPrices = new int[percents.length]; for(int i = 0; i < percents.length; i++) { emoticonPrices[i] = emoticons[i] / 10 * percentMap.get(percents[i]); } // 사용자별 구매 가격 계산 (이모티콘 플러스 고려 전) long[] totalPricesPerUsers = new long[users.length]; for (int i = 0; i < percents.length; i++) { List<Integer> buyers = emoticonBuyers[i]; for (int buyer : buyers) { totalPricesPerUsers[buyer] += emoticonPrices[i]; } } // 이모티콘 플러스 가입자 수 boolean[] isPlusUser = new boolean[users.length]; int plusUserCnt = 0; for (int i = 0; i < users.length; i++) { if (totalPricesPerUsers[i] >= users[i][1]) { isPlusUser[i] = true; plusUserCnt++; } } if (maxPlusUser > plusUserCnt) { return; } // 이모티콘 플러스 고려하여 판매액 계산 long totalPrice = 0L; for (int i = 0; i < users.length; i++) { if (!isPlusUser[i]) { totalPrice += totalPricesPerUsers[i]; } } if (maxPlusUser < plusUserCnt) { maxPlusUser = plusUserCnt; maxSale = totalPrice; } else { // maxPlusUser == plusUserCnt 인 경우 maxSale = Math.max(maxSale, totalPrice); } } static List<Integer>[] makeEmoticonBuyers(int[] percents) { List<Integer>[] emoticonBuyers = new ArrayList[percents.length]; for (int i = 0; i < percents.length; i++) { int percent = percents[i]; emoticonBuyers[i] = new ArrayList<>(); for (int j = 0; j < users.length; j++) { if (percent >= users[j][0]) { emoticonBuyers[i].add(j); } } } return emoticonBuyers; } }
13, 15, 18번 테스트케이스에서 틀렸었다.
부동 소수점연산은 근사값을 저장하기 때문에 이모티콘의 할인된 가격을 계산하면서 틀린 것이다.
[기존 코드]
static final Map<Integer, Double> percentMap = Map.of(10, 0.9, 20, 0.8, 30, 0.7, 40, 0.6); ``` private void event(int[] percents) { ``` // 할인된 이모티콘 가격 int[] emoticonPrices = new int[percents.length]; for(int i = 0; i < percents.length; i++) { emoticonPrices[i] = (int) (emoticons[i] * percentMap.get(percents[i])); } ```` }
위 코드에서 percentMap.get(percents[i]) 를 사용해서 곱셈을 하면 double 즉, 실수값이 반환된다. 하지만, 이는 결과값이 5400 이었어도 5400.0000001 이 저장되었을 수도 있다.
그래서 모조리 정수 연산으로 바꾸어서 계산하도록 수정했다.
[수정한 코드]
static final Map<Integer, Integer> percentMap = Map.of(10, 9, 20, 8, 30, 7, 40, 6); ``` private void event(int[] percents) { ``` // 할인된 이모티콘 가격 int[] emoticonPrices = new int[percents.length]; for(int i = 0; i < percents.length; i++) { emoticonPrices[i] = emoticons[i] / 10 * percentMap.get(percents[i]); } ```` }
percentMap에 저장되는 타입을 <Integer, Integer> 으로 수정하고, emoticons[i] / 10 * percentMap.get(percents[i]) 처럼 정수만 사용하도록 수정했다.
[기억하자]
실수연산을 할 때는 부동소수점의 오류를 주의하자. 3.2 를 저장했어도 실제로는 3.20000000001 이 저장되어 추후 결과값이 완전히 달라질 수 있다.
따라서 다음과 같은 해결책으로 부동소수점의 오류를 피하자.
- 최대한 정수로 연산하기
- 10 * 0.8 -> 10 / 10 * 8 처럼 정수만을 사용하도록 수정
- Math.round(v)
- Math.round() 를 해주면 소수점 첫째 자리까지 반올림해준다.
그리고 이중 (혹은 그 이상의) for 문을 사용하고, 각각 인덱싱을 위한 변수로 쓰인다면 올바른 배열 혹은 리스트에 해당 인덱싱이 쓰였는지 조심!!하자.
'코딩 테스트' 카테고리의 다른 글
[프로그래머스] 징검다리 건너기 (자바) (0) 2025.03.28 [백준] 1806번 부분합 자바(Java) (0) 2025.03.25 [프로그래머스] 표현 가능한 이진 트리 자바 (0) 2025.03.19 [백준] 우주신과의 교감 1774번 자바 (0) 2025.03.19 [백준] 26093 고양이 목에 리본 달기 (DP) (0) 2024.06.26 - 최대한 정수로 연산하기