알고리즘/프로그래머스 - JS

[프로그래머스-JS] level.2 이모티콘 할인 행사 ⭐️⭐️

개발자성장기 2023. 6. 13. 13:46
반응형

 

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr


📚 나의 풀이 

 

이 문제는 부동 소수점 오차를 조심해야한다. 

 

users의 형태 : users = [ 비율, 가격] 

 

📃 문제 풀이 순서

1️⃣  이모티콘 할인율 (10%, 20%, 30%, 40%)중에서 비율보다 낮은 할인율은 제거

function getDiscountRates(users) {
    const minRate = Math.min(...users.map(([discountRate,_]) => discountRate))
    return [40, 30, 20, 10].filter((rate) => rate >= minRate)
}

 

2️⃣ emoticons이 할인되어 책정될 수 있는 모든 가격 리스트를 만든다. 

function generateDiscountCombinations(discount, emoticons) {
  const combinations = [];
    // 부동 소수 때문에  0.6을 바로 사용하지 않고 x*6/10을 사용
    const count = {
        40 : 6,
        30 : 7,
        20 : 8,
        10 : 9
    }

  const backtrack = (discountIdx=0, currentCombo=[]) => {
    if (currentCombo.length === emoticons.length) {
      combinations.push([...currentCombo]);
      return;
    }

    for (let i = discountIdx; i < discount.length; i++) {
      currentCombo.push([
         Math.floor((emoticons[currentCombo.length] * count[discount[i]])/10),
         discount[i]
      ]);
      backtrack(discountIdx, currentCombo);
      currentCombo.pop();
    }
  }
  backtrack();
  return combinations;
}

 입출력 예#1 을 기준으로  generateDiscountCombinations()를 호출하면 생성되는 배열은 아래와 같다. 

[ 할인율이 적용된 이모티콘, 할인율]

 

 

3️⃣ 2번으로 만든 배열로 users 배열을 사용하여  이모티콘 플러스를 몇명이 가입했고 그 때 이모티콘 판매액이 얼마인지 나타내는 배열 생성

function getProfits(discountCombinations, users) {
    const profits = []    
    
    discountCombinations.forEach((discountCombination, index) => {
        const profit = {
            "emoticonPlus" : 0,
            "sales" : 0
        }
    
        users.forEach(([discountRate,limitPrice]) => {
            const purchasedUser = discountCombination.filter(([_, desiredRate]) => desiredRate >= discountRate)
            const totalPurchases = purchasedUser.reduce((acc,[pri,_]) => acc += pri, 0)
            const isBuyEmoticonPlus = totalPurchases >= limitPrice
            if(isBuyEmoticonPlus) {
                profit.emoticonPlus+= 1
                return
            } 
            profit.sales += totalPurchases
        })
        profits.push(profit)
    })
    return profits.map(({emoticonPlus, sales}) => [emoticonPlus,sales])
}

 

입출력 예#1 을 기준으로 getProfits() 을 호출 하면 아래와 같다.

[[emoticonPlus, emoticonsSales]...]

 

 

 

4️⃣  카카오톡 목표에 맞게 정렬한다. 

profits.sort(([emoticonPlusA, emoticonsSalesA],[emoticonPlusB, emoticonsSalesB]) => {
        if(emoticonPlusB === emoticonPlusA) return emoticonsSalesB - emoticonsSalesA
        return emoticonPlusB - emoticonPlusA
    })

이모티콘 플러스 서비스 가입자 수가 동일하면 이모티콘 판매액을 기준으로 내림차순 정렬하기 

 

 

 

 

전체 코드

function solution(users, emoticons) {
    // 40~10% 할인율중에서 users의 최소 비율보다 작은 할인율 제거
    const discountRates = getDiscountRates(users)
    
    // emoticons이 할인되어 책정될 수 있는 모든 가격 리스트
    const discountCombinations = generateDiscountCombinations(discountRates, emoticons);
    // [[emoticonPlus, emoticonsSales]...]
    const profits = getProfits(discountCombinations, users)

    // 이모티콘 플러스 서비스 가입자 수를 내림차순으로 정렬하고 서비스 가입자 수가 같으면 판매액을 내림차순으로 정렬
    profits.sort(([emoticonPlusA, emoticonsSalesA],[emoticonPlusB, emoticonsSalesB]) => {
        if(emoticonPlusB === emoticonPlusA) return emoticonsSalesB - emoticonsSalesA
        return emoticonPlusB - emoticonPlusA
    })

    return profits[0]
}

function getDiscountRates(users) {
    const minRate = Math.min(...users.map(([discountRate,_]) => discountRate))
    return [40, 30, 20, 10].filter((rate) => rate >= minRate)
}


function generateDiscountCombinations(discount, emoticons) {
  const combinations = [];
    // 부동 소수 때문에  0.6을 바로 사용하지 않고 x*6/10을 사용
    const count = {
        40 : 6,
        30 : 7,
        20 : 8,
        10 : 9
    }

  const backtrack = (discountIdx=0, currentCombo=[]) => {
    if (currentCombo.length === emoticons.length) {
      combinations.push([...currentCombo]);
      return;
    }

    for (let i = discountIdx; i < discount.length; i++) {
      currentCombo.push([
         Math.floor((emoticons[currentCombo.length] * count[discount[i]])/10),
         discount[i]
      ]);
      backtrack(discountIdx, currentCombo);
      currentCombo.pop();
    }
  }
  backtrack();
  return combinations;
}


function getProfits(discountCombinations, users) {
    const profits = []    
    
    discountCombinations.forEach((discountCombination, index) => {
        const profit = {
            "emoticonPlus" : 0,
            "sales" : 0
        }
    
        users.forEach(([discountRate,limitPrice]) => {
            const purchasedUser = discountCombination.filter(([_, desiredRate]) => desiredRate >= discountRate)
            const totalPurchases = purchasedUser.reduce((acc,[pri,_]) => acc += pri, 0)
            const isBuyEmoticonPlus = totalPurchases >= limitPrice
            if(isBuyEmoticonPlus) {
                profit.emoticonPlus+= 1
                return
            } 
            profit.sales += totalPurchases
        })
        profits.push(profit)
    })
    return profits.map(({emoticonPlus, sales}) => [emoticonPlus,sales])
}

 

반응형