๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Trouble Shooting

์•Œ๊ณ ๋ฆฌ์ฆ˜, FE ์‹ค๋ฌด์— ์ ์šฉํ•˜๊ธฐ

๐Ÿ“– ๊ฐœ์š”

์ฝ”๋”ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ๊ณต๋ถ€ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ง€์‹๋“ค์€ ๊ฐœ๋ฐœ ์‹ค๋ฌด์—์„œ ์‚ฌ์šฉํ•  ์ผ์ด ์—†์„๊นŒ?

๊ฐœ๋ฐœ ์˜์—ญ, ๊ฐœ๋ฐœ์ž์˜ ์—ญ๋Ÿ‰, ๊ฐœ๋ฐœ ํ™˜๊ฒฝ๋งˆ๋‹ค ๋‹ค๋ฅผ ๊ฒƒ์ด๋‹ค.

 

์ด์— ๋ณธ์ธ ์–˜๊ธฐ๋ฅผ ํ•˜์ž๋ฉด ์›น ํ”Œ๋žซํผ ์„œ๋น„์Šค์˜ FE ๊ฐœ๋ฐœ์ž์ด๋ฉฐ ์ฃผ๋กœ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์ง€๋Š” ํ™”๋ฉด์„ ๊ฐœ๋ฐœํ•œ๋‹ค.

๋ณดํ†ต ํ™”๋ฉด ๊ฐœ๋ฐœ์ด๋ผ ํ•จ์€

  • ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค, ์ธํ„ฐ๋ ‰์…˜ ๊ฐœ๋ฐœ
  • ์„œ๋ฒ„ API ์š”์ฒญ/์‘๋‹ต ์ฒ˜๋ฆฌ

์ผ ๊ฒƒ์ด๋‹ค.

 

๋ฐฉ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ์กฐํšŒํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ์—†๊ณ , ์–ด๋Š์ •๋„ ๊ฐ€๊ณต๋˜์–ด ์‘๋‹ต๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์„œ๋ฒ„์—์„œ ๋ฐ›์•„์„œ ์‚ฌ์šฉํ•˜๋‹ค๋ณด๋‹ˆ

๋ฐ์ดํ„ฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ํƒ์ƒ‰ํ•˜๊ณ  ์ฒ˜๋ฆฌํ•˜๋ ค๋Š” ๊ณ ๋ฏผ๋ณด๋‹ค๋Š” ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค์™€ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ์ตœ์ ํ™”์— ๋Œ€ํ•œ ๊ณ ๋ฏผ์„ ์ฃผ๋กœ ํ–ˆ์—ˆ๋‹ค.

 

์ตœ๊ทผ์—๋Š” ํ‰์†Œ๋ณด๋‹ค ๋ฐ์ดํ„ฐ์˜ ํšจ๊ณผ์ ์ธ ํƒ์ƒ‰ ๋ฐ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ ์ธ ์ ‘๊ทผ์„ ์š”๊ตฌํ•˜๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ–ˆ๊ณ 

์ด๋ฅผ ์ •๋ฆฌํ•˜์—ฌ ๊ธฐ๋กํ•ด๋‘๊ณ ์ž ํ•œ๋‹ค.

 

๐Ÿฅธ ๋ฌธ์ œ

์ด์Šˆ๋Š” ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ๋ฆฌํŒฉํ† ๋งํ•˜๋Š” ๊ณผ์ •์—์„œ ์žˆ์—ˆ๋‹ค.

ํšŒ์‚ฌ ์ฝ”๋“œ์™€ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ๊ทธ๋Œ€๋กœ ๊ณต๊ฐœํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ตœ๋Œ€ํ•œ ์ถ”์ƒํ™”ํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ์ •์˜ํ•ด ๋ณด์ž๋ฉด,

// ๊ตฌ๋งคํ•˜๋ ค๋Š” ์ƒํ’ˆ๋“ค๊ณผ ๊ฐ ์ƒํ’ˆ๋ณ„ ์ ์šฉ๊ฐ€๋Šฅํ•œ ์ฟ ํฐ ๋ฐฐ์—ด์ด ์ฃผ์–ด์กŒ์„ ๋•Œ, 
// ์•„๋ž˜ ์กฐ๊ฑด๋“ค์„ ๋งŒ์กฑํ•˜๋Š” ์ด ์ตœ๋Œ€ ํ• ์ธ ๊ธˆ์•ก์„ ๊ณ„์‚ฐํ•œ๋‹ค.

// ๊ฐ™์€ ์ฟ ํฐ์€ ๊ฐ™์€ id๋ฅผ ๊ฐ€์ง„๋‹ค.
// ์ฟ ํฐ์€ ๊ธˆ์•ก ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌ๋˜์–ด ์žˆ๋‹ค.
// ๊ฐ ์ƒํ’ˆ์€ ํ•˜๋‚˜์˜ ์ฟ ํฐ๋งŒ ์ ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.
// ์ฟ ํฐ์€ ์žฌ๊ณ ๊ฐ€ ์žˆ์–ด์•ผ ์ ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.
// ์ƒํ’ˆ์˜ ์ตœ๋Œ€ ๊ฐœ์ˆ˜๋Š” 20์ด๋‹ค. (orderItems.length <= 20)

// ์ƒํ’ˆ ํƒ€์ž…
type OrderItem = {
  coupons: {
    id: number
    price: number // ํ• ์ธ ๊ธˆ์•ก
    remain: number // ์ž”์—ฌ ๊ฐœ์ˆ˜
  }[]
}

// ์•„๋ž˜ orderItems ๋ฐฐ์—ด์ด ์ฃผ์–ด์กŒ์„ ๋•Œ, id:1, id:2 ์ด ๊ฐ๊ฐ ์ ์šฉ๋˜์–ด 3000 ์ด ์‘๋‹ต๋˜์–ด์•ผ ํ•œ๋‹ค.
orderItems = [
  {coupons: [{id:1, price: 2000, remain: 1}]},
  {coupons: 
    [
      {id:1, price: 2000, remain: 1},
      {id:2, price: 1000, remain: 2}
    ]
  }
]

 

์ •๋„๊ฐ€ ๋  ๊ฒƒ์ด๋‹ค.

 

Greedy

๊ธฐ์กด ์ฝ”๋“œ๋Š” ์ด๋ฅผ ๊ทธ๋ฆฌ๋””(Greedy) ํ•œ ๋ฐฉ์‹์œผ๋กœ ๊ณ„์‚ฐํ•˜๊ณ  ์žˆ์Œ์„ ๋ฐœ๊ฒฌํ–ˆ๋‹ค.

๊ฐ„๋‹จํ•˜๊ฒŒ ์ฝ”๋“œ๋กœ ์˜ฎ๊ฒจ๋ณด์ž๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ์‹์ด๋‹ค.

// ์ฟ ํฐ์˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€๋ฅผ ์ถ”์ ํ•˜๋Š” ๊ฐ์ฒด
let couponUsage = {};

// ์ด ํ• ์ธ ๊ธˆ์•ก์„ ๊ณ„์‚ฐ
let totalDiscount = 0;

// ๊ฐ ์ƒํ’ˆ๋ณ„๋กœ ์ตœ๋Œ€ ํ• ์ธ ์ ์šฉ
orderItems.forEach(item => {
  let maxDiscount = 0;
  let appliedCouponId = null;

  item.coupons.forEach(coupon => {
    // ํ•ด๋‹น ์ฟ ํฐ์ด ์•„์ง ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๊ณ , ์ตœ๋Œ€ ํ• ์ธ ๊ธˆ์•ก๋ณด๋‹ค ํฐ ๊ฒฝ์šฐ
    if (couponUsage[coupon.id] > 0 && coupon.price > maxDiscount) {
      maxDiscount = coupon.price;
      appliedCouponId = coupon.id;
    }
  });

  // ์ฟ ํฐ ์ ์šฉ
  if (appliedCouponId !== null) {
    totalDiscount += maxDiscount;
    couponUsage[appliedCouponId]--; // ์‚ฌ์šฉ๋œ ์ฟ ํฐ์˜ ์žฌ๊ณ  ๊ฐ์†Œ
  }
});

 

 

orderItems๊ฐ€ ์œ„์˜ ์˜ˆ์‹œ์ธ ๊ฒฝ์šฐ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰์‹œ์ผœ๋ณด๋ฉด totalDiscount์— 3000์ด ํ• ๋‹น๋  ๊ฒƒ์ด๋‹ค.

orderItems = [
  {coupons: [{id:1, price: 2000, remain: 1}]},
  {coupons: 
    [
      {id:1, price: 2000, remain: 1},
      {id:2, price: 1000, remain: 2}
    ]
  }
]

 

ํ•˜์ง€๋งŒ ๋ฌธ์ œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด orderItems ์›์†Œ์˜ ์ˆœ์„œ๊ฐ€ ๋ฐ”๋€Œ๊ฒŒ ๋œ๋‹ค๋ฉด ๋‹ค๋ฅธ ๊ฐ’์ด ํ• ๋‹น๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. (id:1 ๋งŒ ์ ์šฉ๋˜์–ด 2000 ํ• ๋‹น)

orderItems = [
  {coupons: 
    [
      {id:1, price: 2000, remain: 1},
      {id:2, price: 1000, remain: 2}
    ]
  },
  {coupons: [{id:1, price: 2000, remain: 1}]}
]

 

์ตœ๋Œ€ ํ• ์ธ ๊ธˆ์•ก์€ orderItems ์›์†Œ์˜ ์ˆœ์„œ์™€ ์ƒ๊ด€์—†์ด ์ผ์ •ํ•ด์•ผ ํ•œ๋‹ค.

ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ๊ณ„์† ๊ทธ๋ฆฌ๋””ํ•˜๊ฒŒ ์ ‘๊ทผํ•˜์ž๋ฉด, orderItems๋ฅผ ํŠน์ • ์กฐ๊ฑด์œผ๋กœ ์ •๋ ฌํ•œ ๋’ค ์ตœ๋Œ€ ํ• ์ธ ๊ธˆ์•ก์„ ๊ณ„์‚ฐํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์„ ๊ฒƒ์ด๋‹ค.

 

ํ•˜์ง€๋งŒ ๊ฒฝํ—˜์ƒ ๊ทธ๋ฆฌ๋””ํ•˜๊ฒŒ ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ์‹์€ ํ•œ๊ณ„๊ฐ€ ์žˆ๋‹ค. ์ดํ›„์— ์ƒˆ๋กœ์šด ์ฟ ํฐ ์‚ฌ์šฉ ๊ทœ์น™์ด ์ถ”๊ฐ€๋˜์—ˆ์„ ๋•Œ ํ™•์žฅ์„ฑ์— ์ทจ์•ฝํ•˜๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ฒฝํ—˜์ƒ ๊ทธ๋ฆฌ๋””ํ•˜๊ฒŒ ์ ‘๊ทผํ•˜์—ฌ ์ตœ์ ์˜ ํ•ฉ์„ ๋‚ผ ์ˆ˜ ์—†์„ ๋•Œ brute force ๋ฐฉ์‹์œผ๋กœ ์ ‘๊ทผํ•˜๋ฉด ๋„์›€์ด ๋œ๋‹ค.

 

Brute Force (recursively)

๋”ฐ๋ผ์„œ ์ฃผ์–ด์ง„ orderItems ์˜ ์ ์šฉ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ์ฟ ํฐ ํ• ์ธ ๊ธˆ์•ก์„ ์žฌ๊ท€์ ์œผ๋กœ ๊ณ„์‚ฐํ•ด์„œ ๋น„๊ตํ•ด๋ณด๊ณ ์ž ํ–ˆ๋‹ค.

const orderItems = [
  {coupons: [{id: 1, price: 2000, remain: 1}, {id: 2, price: 1000, remain: 2}]},
  {coupons: [{id: 1, price: 2000, remain: 1}]}
];

// ์ฟ ํฐ ์‚ฌ์šฉ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฐ์ฒด
let couponUsage = {};

function getMaxDiscount(orderItems, index = 0, usedCoupons = {}, currentDiscount = 0) {
  if (index >= orderItems.length) {
    // ๋ชจ๋“  ์ƒํ’ˆ์— ๋Œ€ํ•œ ์ฟ ํฐ ์ ์šฉ์„ ์‹œ๋„ํ•œ ๊ฒฝ์šฐ, ํ˜„์žฌ๊นŒ์ง€์˜ ํ• ์ธ ๊ธˆ์•ก์„ ๋ฐ˜ํ™˜
    return currentDiscount;
  }

  let maxDiscount = currentDiscount; // ํ˜„์žฌ๊นŒ์ง€์˜ ์ตœ๋Œ€ ํ• ์ธ ๊ธˆ์•ก์„ ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ ์„ค์ •

  // ํ˜„์žฌ ์ƒํ’ˆ์— ์ ์šฉ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ์ฟ ํฐ์— ๋Œ€ํ•ด ๋ฐ˜๋ณต
  for (let coupon of orderItems[index].coupons) {
    const couponId = coupon.id;
    if (!usedCoupons[couponId] || usedCoupons[couponId] < coupon.remain) {
      // ์ฟ ํฐ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ
      const newUsedCoupons = {...usedCoupons};
      newUsedCoupons[couponId] = (newUsedCoupons[couponId] || 0) + 1;

      // ํ˜„์žฌ ์ฟ ํฐ์„ ์ ์šฉํ•˜๊ณ  ๋‹ค์Œ ์ƒํ’ˆ์œผ๋กœ ๋„˜์–ด๊ฐ€ ์ตœ๋Œ€ ํ• ์ธ ๊ธˆ์•ก์„ ๊ณ„์‚ฐ
      const newDiscount = getMaxDiscount(orderItems, index + 1, newUsedCoupons, currentDiscount + coupon.price);
      maxDiscount = Math.max(maxDiscount, newDiscount);
    }
  }

  // ํ˜„์žฌ ์ƒํ’ˆ์— ์–ด๋–ค ์ฟ ํฐ๋„ ์ ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋„ ๊ณ ๋ ค
  const noCouponDiscount = getMaxDiscount(orderItems, index + 1, usedCoupons, currentDiscount);
  maxDiscount = Math.max(maxDiscount, noCouponDiscount);

  return maxDiscount;
}

const totalMaxDiscount = getMaxDiscount(orderItems);
console.log(totalMaxDiscount); // 3000

 

์ด์ œ ์–ด๋–ค ์ˆœ์„œ์˜ orderItems๊ฐ€ ๋„˜์–ด์™€๋„ ์ ์šฉ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ์ฟ ํฐ ํ• ์ธ ๊ธˆ์•ก์„ ๊ณ„์‚ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•ญ์ƒ ์ตœ์ ์˜ ํ•ด๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

 

...๊ณผ์—ฐ ์ด์ œ ๋” ์ด์ƒ ๋ฌธ์ œ๊ฐ€ ์—†์„๊นŒ? ๐Ÿค”

 

์ฝ”๋”ฉ ํ…Œ์ŠคํŠธ๋ฅผ ๊ณต๋ถ€ํ•˜๋ฉฐ ํ•ญ์ƒ ๊ฒฝํ—˜ํ•˜๋Š” ๊ฒƒ์ด์ง€๋งŒ, ๋‹ค๋ฅธ ์ผ€์ด์Šค๋Š” ๋‹ค pass ํ•˜๋Š”๋ฐ ํ•ญ์ƒ ์‹œ๊ฐ„ ๋ณต์žก๋„์—์„œ ์‹คํŒจํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋ณดํ†ต brute force ๋ฐฉ์‹์œผ๋กœ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์„ ๋•Œ ์ด๋Ÿฐ ๊ฒฝ์šฐ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

 

์‹ค์ œ๋กœ ์ด ์ฃผ๋ฌธํ•  ์ƒํ’ˆ์˜ ๊ฐœ์ˆ˜๋Š” 20๊ฐœ๊นŒ์ง€ ๊ฐ€๋Šฅํ–ˆ๊ณ  (orderItems.length <= 20)

๊ฐ ์ƒํ’ˆ์— ์ฟ ํฐ์ด 2๊ฐœ์”ฉ๋งŒ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋„ 2^20 ๋ฒˆ ์ˆœํ™˜์„ ํ•˜๊ฒŒ ๋œ๋‹ค.

์ด๋ฅผ jest๋กœ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ํ…Œ์ŠคํŠธ ํ•ด๋ดค์„ ๋•Œ ๊ต‰์žฅํžˆ ๊ธด ์‹œ๊ฐ„๋™์•ˆ ์‹คํ–‰์ด ๋˜์—ˆ๊ณ , (macbook pro m3, ram 36gb 5min ์ด์ƒ)

JS ๋Š” ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ์–ธ์–ด์ด๊ธฐ ๋•Œ๋ฌธ์— ์œ„ ํ•จ์ˆ˜๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ฉˆ์ถฐ์žˆ์„ ๊ฒƒ์ด๋‹ค. ๐Ÿ˜ฑ

 

์ด๋Š” ์ ˆ๋Œ€ ํ—ˆ์šฉ ๋ถˆ๊ฐ€ ์ˆ˜์น˜์ด๋ฉฐ ์ด๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ๋ชจ์ƒ‰ํ•ด์•ผํ–ˆ๋‹ค.

 

Backtracking

๋ฐฑํŠธ๋ž˜ํ‚น์€ ๋ธŒ๋ฃจํŠธ ํฌ์Šค(Brute Force) ํƒ์ƒ‰์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋˜, ํ•ด๊ฐ€ ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์—†๋Š” ๊ฒฝ์šฐ ๊ทธ ๊ฒฝ๋กœ๋ฅผ ์กฐ๊ธฐ์— ํฌ๊ธฐ(Pruning)ํ•˜๊ณ  ๋‹ค๋ฅธ ๊ฒฝ๋กœ๋ฅผ ์‹œ๋„ํ•˜๋Š” "๊ฐ€์ง€์น˜๊ธฐ" ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ ํšจ์œจ์„ฑ์„ ๋†’์ด๋Š” ๋ฐฉ์‹์ด๋‹ค.

 

orderItem์„ ์žฌ๊ท€์ ์œผ๋กœ ์ˆœํšŒํ•˜๋ฉด์„œ, ์•ž์œผ๋กœ ๋‚จ์€ orderItem๋“ค์˜ '๊ฐ€๋Šฅํ•œ ์ตœ๋Œ€์˜ ์ฟ ํฐ ํ• ์ธ ๊ธˆ์•ก' ํ•ฉ์„ ๊ณ„์‚ฐํ•œ๋‹ค.

๋งŒ์•ฝ 'ํ˜„์žฌ ์ฟ ํฐ ํ• ์ธ ๊ธˆ์•ก (currentDiscount)'  + '๊ฐ€๋Šฅํ•œ ์ตœ๋Œ€์˜ ์ฟ ํฐ ํ• ์ธ (possibleMaxDiscount)' ์ด

๊ธฐ์กด '์ตœ๋Œ€ ํ• ์ธ ๊ธˆ์•ก (maxDiscount)' ๋ณด๋‹ค ๋‚ฎ๋‹ค๋ฉด, ํ•ด๋‹น ๊ฒฝ๋กœ๋Š” ๋” ์ด์ƒ ํƒ์ƒ‰ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

 

๋‹ค์Œ์€ backtracking ๋ฐฉ์‹์„ ์ถ”๊ฐ€ํ•œ ์ฝ”๋“œ์ด๋‹ค.

const getMaxDiscount = (orderItems) => {
  let maxDiscount = 0 // ์ตœ๋Œ€ ํ• ์ธ์•ก์„ ์ €์žฅํ•˜๋Š” ๋ณ€์ˆ˜
  const couponStocks = {} // ๊ฐ ์ฟ ํฐ์˜ ์žฌ๊ณ ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฐ์ฒด

  // ๊ฐ orderItem์˜ ์ตœ๋Œ€ ํ• ์ธ์•ก์„ ์ €์žฅ
  const maxDiscountPerOrderItems = orderItems.map(orderItem => orderItem.coupons[0].price)
  const getPossibleMaxDiscountOfRestOrderItems = (currentIndex: number) => {
    return maxDiscountPerOrderItems.slice(currentIndex).reduce((acc, cur) => acc + cur, 0)
  }

  // ๋ฐฑํŠธ๋ž˜ํ‚น ํ•จ์ˆ˜ ์ •์˜
  function backtrack(currentIndex: number, currentDiscount: number) {
    // ๋ชจ๋“  orderItem ๋ฅผ ์ฒ˜๋ฆฌํ•œ ๊ฒฝ์šฐ, ์ตœ๋Œ€ ํ• ์ธ์•ก์„ ์—…๋ฐ์ดํŠธ
    if (currentIndex === orderItems.length) {
      maxDiscount = Math.max(maxDiscount, currentDiscount)
      return
    }

    // ํ˜„์žฌ ํ• ์ธ ๊ธˆ์•ก๊ณผ ๋‚˜๋จธ์ง€ orderItems ์˜ ์ตœ๋Œ€ ํ• ์ธ ๊ธˆ์•ก์˜ ํ•ฉ์ด ๊ธฐ์กด ์ตœ๋Œ€ ํ• ์ธ ๊ธˆ์•ก๋ณด๋‹ค ์ž‘์€ ๊ฒฝ์šฐ, ํƒ์ƒ‰ ์ค‘๋‹จ
    if (currentDiscount + getPossibleMaxDiscountOfRestOrderItems(currentIndex) <= maxDiscount) {
      return
    }

    // ํ˜„์žฌ property ์˜ ๋ชจ๋“  ์ฟ ํฐ์„ ์ˆœํšŒ
    for (const coupon of orderItems[currentIndex].coupons) {

      // ์ฟ ํฐ์˜ ์žฌ๊ณ ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ๋งŒ ์ฒ˜๋ฆฌ
      if (coupon.remain <= 0) continue

      if (!couponStocks[coupon.id] || couponStocks[coupon.id] < coupon.remain) {
        // ์ฟ ํฐ ์ ์šฉ: ์žฌ๊ณ  ๊ฐ์†Œ ๋ฐ ํ• ์ธ์•ก ์ฆ๊ฐ€
        couponStocks[coupon.id] = (couponStocks[coupon.id] || 0) + 1
        backtrack(currentIndex + 1, currentDiscount + coupon.price)

        // ๋ฐฑํŠธ๋ž˜ํ‚น: ์ฟ ํฐ ์ ์šฉ ์ทจ์†Œ
        couponStocks[coupon.id] -= 1
      }
    }

    // ํ˜„์žฌ property ์—์„œ ์ฟ ํฐ์„ ์ ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋„ ํƒ์ƒ‰
    backtrack(currentIndex + 1, currentDiscount)
  }

  // ๋ฐฑํŠธ๋ž˜ํ‚น ์‹œ์ž‘
  backtrack(0, 0)

  return maxDiscount
}

 

์ฟ ํฐ ๋ฐฐ์—ด๋“ค์€ ์ด๋ฏธ ๊ฐ€๊ฒฉ ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌ ๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋Œ€๋ถ€๋ถ„์˜ ์ตœ์ ์ธ ์ตœ๋Œ€ํ• ์ธ ๊ธˆ์•ก๋“ค์ด ๋จผ์ € ๊ฒฐ์ •์ด ๋˜์–ด ๋งŽ์€ ๊ฒฝ๋กœ๋ฅผ '๊ฐ€์ง€์น˜๊ธฐ' ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋œ๋‹ค.

๐Ÿ˜Ž ๋งˆ์น˜๋ฉฐ

์‹ค์ œ ์šด์˜๋˜๊ณ  ์žˆ๋Š” ์ฝ”๋“œ์™€ ์ƒํ’ˆ, ์ฟ ํฐ ํƒ€์ž… ์ •์˜๋Š” ํ›จ์”ฌ ๋” ๋ณต์žกํ•˜๋‹ค.

์šด์˜ ์ฝ”๋“œ๊ฐ€ ๊ทธ๋ฆฌ๋””ํ•˜๊ฒŒ ์ž‘์„ฑ๋˜์–ด ์žˆ๋‹ค๊ณ  ํ–ˆ์ง€๋งŒ, ๊ทธ๋ฆฌ๋””ํ•˜๊ฒŒ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๊ต‰์žฅํžˆ ๋งŽ์€ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์ด ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค.

์ฒซ ๊ฐœ๋ฐœ ์ดํ›„ ๋งŽ์€ ๊ธฐ๋Šฅ๊ณผ ์ •์ฑ…๋“ค์ด ์ถ”๊ฐ€๋œ ๊ฒƒ์œผ๋กœ ๋ณด์ด๊ณ  ์ด๋ฅผ ๊ธฐ์กด ์ฝ”๋“œ์—์„œ ํ•ด๊ฒฐํ•˜๋‹ค๋ณด๋‹ˆ ๋ณต์žก๋„๊ฐ€ ์˜ฌ๋ผ๊ฐ€๊ณ  ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์ด ๋–จ์–ด์ง€๊ฒŒ ๋˜์—ˆ๋‹ค.

 

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์ตœ๋Œ€ํ•œ ์ถ”์ƒํ™”ํ•˜๋Š” ๊ณผ์ •์—์„œ, ๋ฌธ์ œ๋ฅผ ๊ต‰์žฅํžˆ ๋‹จ์ˆœํ™”ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

๋˜ํ•œ, ์ด ๊ณผ์ •์„ ํ†ตํ•ด ๊ธฐ์กด ์ฝ”๋“œ์— ํฌํ•จ๋˜์–ด ์žˆ๋˜ ์ผ๋ถ€ ๋ถˆํ•„์š”ํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋ฐœ๊ฒฌํ•˜๊ณ  ์ œ๊ฑฐํ•จ์œผ๋กœ์จ,

์ตœ์ ์˜ ํƒ์ƒ‰ ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋‚ผ ์ˆ˜ ์žˆ์—ˆ๋‹ค. ( ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์žˆ์„ ์ˆ˜๋„...? )

 

์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ง€์‹์„ ํ™œ์šฉํ•ด ์‹ค์ œ ์šด์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ ์ด๋ฒˆ ๊ฒฝํ—˜์€ ๋งค์šฐ ์†Œ์ค‘ํ–ˆ์œผ๋ฉฐ,

์ด๋ฅผ ํ†ตํ•ด ์–ป์€ ํ†ต์ฐฐ๋ ฅ์„ ๋ฐ”ํƒ•์œผ๋กœ ์•ž์œผ๋กœ ๋‹ค์–‘ํ•œ ๋„์ „๋“ค์„ ์„ฑ๊ณต์ ์œผ๋กœ ๊ทน๋ณตํ•ด๋‚˜๊ฐˆ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.