📌 문제
문제 출처 - 링크
문제 설명





알고리즘 분류
- 구현
- 완전 탐색 (브루트포스)
- DFS (재귀)
📋 문제 요약 설명
- 이모티콘마다 할인율은 다를 수 있으며 할인율은 10%, 20%, 30%, 40% 중 하나로 설정된다.
- 사용자는 이코티콘을 구매할 때 정해진 할인율 이상이 되어야지 구매한다. 그리고 할인율 이상인 이모티콘은 모두 구매한다.
- 이모티콘 구매 비용의 합이 일정 금액 이상이 되면 이모티콘 구매를 모두 취소하고, 이모티콘 플러스를 가입한다.
- 이모티콘 플러스 가입자를 최대한 늘리면서 이모티콘 판매액도 가장 많을 때 값을 반환하라
💡 알고리즘 설계 / 접근 방법
- 이모티콘의 할인율을 조합해야 하는데 이모티콘 플러스 서비스에 가장 많이 가입하도록 하기 위해서는 모든 조건을 찾아보는 수밖에 없을 것 같아서 완전 탐색을 생각하게 되었다.
- 완전 탐색을 하려면 모든 조합을 만들어야 하므로 재귀로 구현해야겠다 생각했고, DFS의 재귀 방식을 선택하게 되었다.
- 재귀 함수를 사용하기 위해서 메소드를 만든다.
- 이모티콘마다 10%, 20%, 30%, 40% 중 할인율을 할당하고, 모두 할인율이 정해지면 해당 조합이 최적의 조합인지 확인한다.
- 이모티콘의 할인률을 할당한 다음 재귀 함수를 호출해서 모든 조합을 만들도록 한다.
- 조합은 [10, 10, 10, 10] → [10, 10, 10, 20] → [10, 10, 10, 30] … 순서로 만들어진다.
- 최적의 조합인지 확인하기 위한 메소드를 만든다.
- 사용자마다 이모티콘 구매 비용을 계산하고, 이모티콘 플러스 가입 여부도 확인한다.
- 해당 조합의 총 이모티콘 플러스 가입자 수와 이모티콘 구매 비용으로 이전의 기록과 비교한다.
➕ 보완하기 / 성능 비교
- 작성한 코드 형태가 백트래킹 패턴과 동일하긴 하나 가지치기 없이 전 조합을 평가하기 때문에 백트래킹이라고 보긴 어렵다. 하지만 백트래킹으로도 구현할 수 있는 문제이다.
✅ 풀이
시간 복잡도 → O(4m⋅(u⋅m))
- 할인 조합 생성 부분 (setRateRecur) : O(4m)
- 조합 평가 부분 (findComb) : O(u⋅m)
class Solution {
static int EMOTICON_PLUS;
static int TOTAL_SALES;
static final int[] SALE_RATE = {10, 20, 30, 40};
public int[] solution(int[][] users, int[] emoticons) {
EMOTICON_PLUS = 0;
TOTAL_SALES = 0;
setRateRecur(users, emoticons, 0, new int[emoticons.length]);
return new int[] {EMOTICON_PLUS, TOTAL_SALES};
}
private void setRateRecur(int[][] users, int[] emoticons, int index, int[] rates) {
if (index == emoticons.length) {
findComb(users, emoticons, rates);
return;
}
for (int rate : SALE_RATE) {
rates[index] = rate;
setRateRecur(users, emoticons, index + 1, rates);
}
}
private void findComb(int[][] users, int[] emoticons, int[] rates) {
int emoticonPlus = 0;
int totalSales = 0;
for (int[] user : users) {
int purchase = 0;
int rate = user[0];
int maxPurchase = user[1];
for (int i = 0; i < rates.length; i++) {
if (rate <= rates[i]) {
purchase += (emoticons[i] * (100 - rates[i]) / 100);
}
}
if (maxPurchase <= purchase) emoticonPlus++;
else totalSales += purchase;
}
if (EMOTICON_PLUS < emoticonPlus) {
EMOTICON_PLUS = emoticonPlus;
TOTAL_SALES = totalSales;
}
else if (EMOTICON_PLUS == emoticonPlus) {
TOTAL_SALES = Math.max(totalSales, TOTAL_SALES);
}
}
}