Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Algorithm] 이모티콘 할인행사 #80

Closed
hwangJi-dev opened this issue Jan 19, 2023 · 0 comments
Closed

[Algorithm] 이모티콘 할인행사 #80

hwangJi-dev opened this issue Jan 19, 2023 · 0 comments

Comments

@hwangJi-dev
Copy link
Owner

hwangJi-dev commented Jan 19, 2023

💬 문제

[코딩테스트 연습 - 이모티콘 할인행사](https://school.programmers.co.kr/learn/courses/30/lessons/150368)


💬 Idea

  1. 먼저 이모티콘 수에 맞는 할인율 조합을 구하자
    1. 어떻게 구할 것인가? → dfs 재귀함수를 만들어서 10, 20, 30, 40 각각을 돌며 array에 더한다.
      1. dfs 비교군을 줄이기 위해 user가 갖고 있는 가격 기준의 최저값을 구해 sales를 먼저 필터링해준다.
      2. ex. user = [[40, 10000], [25, 10000]] 의 경우 유저들이 구입할 최저 세일 비율이 30% 이므로 30, 40 만을 갖고 가격 조합을 만들어줄 수 있다. → 시간 절약 !
  2. 할인율 조합을 구한 뒤 해당 조합에서 이모티콘플러스 가입자 수와 판매액이 최댓값인지를 비교하자

💬 풀이

  1. 첫번째 시도 - 시간초과 [정확성 (75/100)]

    var percentArr: Set<[Int]> = []
    func solution(users:[[Int]], emoticons:[Int]) -> [Int] {
        dfs(index: 0, arr: [], max: emoticons.count)
        
        var emtiplusCnt = 0
        var sumSale = 0
        
        for percent in percentArr {
            var cnt = 0
            var sum = 0
            
            for user in users {
                var userSum = 0
                
                for (index, p) in percent.enumerated() {
                    // 유저의 기준비율에 맞는 이모티콘만 선별하기
                    if p >= user[0] {
                        userSum += calDiscountPrice(Double(emoticons[index]), Double(p))
                    }
                }
                
                // 유저의 기준가격을 넘긴다면 이모티콘 플러스 가입시키기
                if userSum >= user[1] {
                    cnt += 1
                } else {
                    sum += userSum
                }
            }
            
            if cnt > emtiplusCnt {
                emtiplusCnt = cnt
                sumSale = sum
            } else if cnt == emtiplusCnt {
                sumSale = sum > sumSale ? sum : sumSale
            }
        }
        
        return [emtiplusCnt, sumSale]
    }
    
    func dfs(index: Int, arr: [Int], max: Int) {
        if index == max {
            percentArr.insert(arr)
            return
        }
        
        for _ in 0..<max {
            dfs(index: index + 1, arr: arr + [10], max: max)
            dfs(index: index + 1, arr: arr + [20], max: max)
            dfs(index: index + 1, arr: arr + [30], max: max)
            dfs(index: index + 1, arr: arr + [40], max: max)
        }
    }
    
    // 이모티콘 할인 가격 계산
    func calDiscountPrice(_ origin: Double, _ percent: Double) -> Int {
        return Int(origin - ((origin / 100) * percent))
    }
    • 이모티콘 할인율 조합을 구하는 dfs부분에서 문제가 있다고 판단했음
  2. 두번째 시도 - dfs 부분 불필요한 코드 제거 → 정답

    1. 최저 0.25 / 최고 3721.27
    var percentArr: [[Int]] = []
    func solution(_ users:[[Int]], _ emoticons:[Int]) -> [Int] {
        let users = users.sorted(by: { $0[0] > $1[0] })
        let sales = [10, 20, 30, 40].filter({ $0 >= users.last![0] })
        
        // 이모티콘의 할인가격 배열 구하기
        dfs(index: 0, arr: [], max: emoticons.count, sales: sales)
        
        var finalEmtiPlusCnt = 0
        var finalSum = 0
        
        for percent in Set(percentArr) {
            var emtiplusCnt = 0
            var sum = 0
            
            for user in users {
                var userSum = 0
                
                for (index, p) in percent.enumerated() {
                    // 유저의 기준비율에 맞는 이모티콘만 선별하기
                    if p >= user[0] {
                        userSum += calDiscountPrice(emoticons[index], p)
                    }
                }
                
                // 유저의 기준가격을 넘긴다면 이모티콘 플러스 가입
                if userSum >= user[1] {
                    emtiplusCnt += 1
                } else {
                    sum += userSum
                }
            }
            
            // 현재 할인 비율 모음이 최대 이모티콘 플러스 가입자를 이끌어내는지 확인
            if emtiplusCnt > finalEmtiPlusCnt {
                finalEmtiPlusCnt = emtiplusCnt
                finalSum = sum
            } else if emtiplusCnt == finalEmtiPlusCnt {
                finalSum = sum > finalSum ? sum : finalSum
            }
        }
        
        return [finalEmtiPlusCnt, finalSum]
    }
    
    func dfs(index: Int, arr: [Int], max: Int, sales: [Int]) {
        if index == max {
            percentArr.append(arr)
            return
        }
        
        for sale in sales {
            dfs(index: index + 1, arr: arr + [sale], max: max, sales: sales)
        }
    }
    
    // 이모티콘 할인 가격 계산
    func calDiscountPrice(_ origin: Int, _ percent: Int) -> Int {
        return origin - ((origin / 100) * percent)
    }
  • 3중 중첩 for문을 제거하고 2중 for문으로 대체한 풀이.

  • dfs에서 조합을 구할 때마다 해당 할인가격 조합의 이모티콘플러스 가입자 수와 판매액이 최댓값인지 비교하기

    • 최저 0.22 / 최고 3809.28
    var finalEmtiPlusCnt = 0
    var finalSum = 0
    var user: [[Int]] = []
    var emoticon: [Int] = []
    
    func solution(users:[[Int]], emoticons:[Int]) -> [Int] {
        user = users
        emoticon = emoticons
        
        dfs(index: 0, arr: [], max: emoticons.count, sales: [10, 20, 30, 40])
        
        return [finalEmtiPlusCnt, finalSum]
    }
    
    func dfs(index: Int, arr: [Int], max: Int, sales: [Int]) {
        // 이모티콘의 할인가격 조합 도출
        if index == max {
            // 해당 할인가격 조합의 이모티콘플러스 가입자 수와 판매액이 최댓값인지 비교
            getResultBySalesComb(arr)
            return
        }
        
        for sale in sales {
            dfs(index: index + 1, arr: arr + [sale], max: max, sales: sales)
        }
    }
    
    // 이모티콘플러스 가입자 수와 판매액 도출 후 최댓값인지 비교하는 메서드
    func getResultBySalesComb(_ arr: [Int]) {
        var emtiplusCnt = 0
        var sum = 0
        
        for u in user {
            var userSum = 0
            
            for (index, p) in arr.enumerated() {
                // 유저의 기준비율에 맞는 이모티콘만 선별
                if p >= u[0] {
                    userSum += calDiscountPrice(emoticon[index], p)
                }
            }
            
            // 유저의 기준가격을 넘긴다면 이모티콘 플러스 가입
            if userSum >= u[1] {
                emtiplusCnt += 1
            } else {
                sum += userSum
            }
        }
        
        // 현재 할인 비율 모음이 최대 이모티콘 플러스 가입자를 이끌어내는지 확인
        if emtiplusCnt > finalEmtiPlusCnt {
            finalEmtiPlusCnt = emtiplusCnt
            finalSum = sum
        } else if emtiplusCnt == finalEmtiPlusCnt {
            finalSum = sum > finalSum ? sum : finalSum
        }
    }
    
    // 이모티콘 할인 가격 계산 메서드
    func calDiscountPrice(_ origin: Int, _ percent: Int) -> Int {
        return origin - ((origin / 100) * percent)
    }
  • dfs 부분 불필요한 코드 제거 && 고차함수 사용하여 비교군 감소

    • 최저 0.34 / 최고 3551.96
    var finalEmtiPlusCnt = 0
    var finalSum = 0
    var user: [[Int]] = []
    var emoticon: [Int] = []
    
    func solution(users:[[Int]], emoticons:[Int]) -> [Int] {
        user = users.sorted(by: { $0[0] > $1[0] })
        emoticon = emoticons
        
        dfs(index: 0, arr: [], max: emoticons.count, sales: [10, 20, 30, 40].filter({ $0 >= user.last![0] }))
        
        return [finalEmtiPlusCnt, finalSum]
    }
    
    func dfs(index: Int, arr: [Int], max: Int, sales: [Int]) {
        // 이모티콘의 할인가격 조합 도출
        if index == max {
            // 해당 할인가격 조합의 이모티콘플러스 가입자 수와 판매액이 최댓값인지 비교
            getResultBySalesComb(arr)
            return
        }
        
        for sale in sales {
            dfs(index: index + 1, arr: arr + [sale], max: max, sales: sales)
        }
    }
    
    // 이모티콘플러스 가입자 수와 판매액 도출 후 최댓값인지 비교하는 메서드
    func getResultBySalesComb(_ arr: [Int]) {
        var emtiplusCnt = 0
        var sum = 0
        
        for u in user {
            var userSum = 0
            
            for (index, p) in arr.enumerated() {
                // 유저의 기준비율에 맞는 이모티콘만 선별
                if p >= u[0] {
                    userSum += calDiscountPrice(emoticon[index], p)
                }
            }
            
            // 유저의 기준가격을 넘긴다면 이모티콘 플러스 가입
            if userSum >= u[1] {
                emtiplusCnt += 1
            } else {
                sum += userSum
            }
        }
        
        // 현재 할인 비율 모음이 최대 이모티콘 플러스 가입자를 이끌어내는지 확인
        if emtiplusCnt > finalEmtiPlusCnt {
            finalEmtiPlusCnt = emtiplusCnt
            finalSum = sum
        } else if emtiplusCnt == finalEmtiPlusCnt {
            finalSum = sum > finalSum ? sum : finalSum
        }
    }
    
    // 이모티콘 할인 가격 계산 메서드
    func calDiscountPrice(_ origin: Int, _ percent: Int) -> Int {
        return origin - ((origin / 100) * percent)
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant