Coding/알고리즘

[알고리즘 TIL] 이모티콘 할인행사

kangplay 2025. 3. 3. 18:35
문제

https://school.programmers.co.kr/learn/courses/30/lessons/150368?language=java

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

프로그래머스 LV2. 시뮬레이션

설명

완전 탐색으로 구한다면, 100(사용자 수)*4(할인율 경우의 수)^7(이모티콘 개수)의 시간복잡도가 예상된다. 이모티콘의 개수가 크지 않아서 완전 탐색으로 통과되는 문제였다.

 

하지만, 4^n의 경우의 수를 구현하는 것이 쉽지 않았던 문제이다.

구현
import java.util.Arrays;

class Solution {

    static int sign = 0; //최대 회원 수
    static int earn = 0; //최대 수익

    public int[] solution(int[][] users, int[] emoticons) {
        int[] answer = new int[2];
        int N = emoticons.length;
        int[] discountEmoticons = new int[N]; // 이모티콘 별 할인율 저장
        Arrays.fill(discountEmoticons, 10); // 10%로 초기화

        int totalCases = (int) Math.pow(4, N); // 4^N 가지의 조합
        for (int i = 0; i < totalCases; i++) {
            //특정 이모티콘들 할인율로 사용자들의 수익과 플러스 가입 수 계산 
            calculate(discountEmoticons, users, emoticons);
            //이모티콘들 할인율 갱신
            nextDiscount(discountEmoticons); // 다음 할인율 조합 생성
        }

        answer[0] = sign;
        answer[1] = earn;
        return answer;
    }

    // 이모티콘 중 하나를 10% 인상시키는 함수
    // 맨 뒷 인덱스부터 10%->...->40%순으로 증가시키며 할인율 고정
    // 해당 인덱스의 할인율을 10퍼 올리거나, 이미 40퍼인 경우 10%로 초기화 후 앞 인덱스 갱신
    private void nextDiscount(int[] discountEmoticons) {
    	//어떤 이모티콘을 인상시킬지 탐색
        int index = discountEmoticons.length - 1;
        while (index >= 0) {
            //해당 인덱스의 할인율이 40퍼 미만인 경우, 10퍼 인상
            if (discountEmoticons[index] < 40) {
                discountEmoticons[index] += 10;//하나 증가했으면 종료
                break;
            } else {
                //해당 인덱스의 할인율이 40퍼인 경우, 10퍼로 초기화의 앞 인덱스 상승
                discountEmoticons[index] = 10;
                index--;
            }
        }
    }

    private void calculate(int[] discountEmoticons, int[][] users, int[] emoticons) {
        int count = 0; // 가입자 수
        int earn_t = 0; // 현재 할인 조합에서의 수익

        for (int[] user : users) {
            int discount = user[0]; // 최소 원하는 할인율
            int price = user[1]; // 구매 한도
            int sum = 0;

            for (int i = 0; i < discountEmoticons.length; i++) {
                if (discountEmoticons[i] >= discount) {
                    sum += (emoticons[i] / 100) * (100 - discountEmoticons[i]); // 할인 적용된 가격
                }
            }

            if (sum >= price) count++; // 구매 한도 초과하면 플러스 가입
            else earn_t += sum; // 아니면 일반 구매 수익 증가
        }

        if (count > sign) {
            sign = count;
            earn = earn_t;
        } else if (count == sign) {
            if (earn < earn_t) earn = earn_t;
        }
    }​