Jieunny의 λΈ”λ‘œκ·Έ

S4) Unit 11. μ•Œκ³ λ¦¬μ¦˜ λ¬Έμ œν’€μ΄(μˆœμ—΄, μ‘°ν•©, Greedy, λ©±μ§‘ν•©) λ³Έλ¬Έ

CodeStates/Training

S4) Unit 11. μ•Œκ³ λ¦¬μ¦˜ λ¬Έμ œν’€μ΄(μˆœμ—΄, μ‘°ν•©, Greedy, λ©±μ§‘ν•©)

Jieunny 2023. 4. 6. 15:37

πŸ“Œ  문제

μžμ‹ μ΄ 감μ˜₯에 κ°„ 사이 μ—°μΈμ΄μ—ˆλ˜ 쀄리아λ₯Ό μ•€λ””μ—κ²Œ 빼앗겨 ν™”κ°€ λ‚œ μ‘°μ§€λŠ” λΈŒλ ˆλ“œ, λ§·κ³Ό ν•¨κ»˜ μ•€λ”” μ†Œμœ μ˜ μΉ΄μ§€λ…Έ μ§€ν•˜μ— μžˆλŠ” 금고λ₯Ό ν„ΈκΈ°λ‘œ ν•©λ‹ˆλ‹€. μ˜¨κ°– νŠΈλž©μ„ 뚫고 λ“œλ””μ–΄ κΈˆκ³ μ— μ§„μž…ν•œ 쑰지와 일행듀. μ‘°μ§€λŠ” 이와쀑에 감μ˜₯μ—μ„œ ν‹ˆν‹ˆμ΄ κ³΅λΆ€ν•œ μ•Œκ³ λ¦¬μ¦˜μ„ μ΄μš©ν•΄ target κΈˆμ•‘μ„ ν›”μΉ  수 μžˆλŠ” λ°©λ²•μ˜ 경우의 수λ₯Ό κ³„μ‚°ν•˜κΈ° μ‹œμž‘ν•©λ‹ˆλ‹€.
 
예λ₯Ό λ“€μ–΄ $50 을 ν›”μΉ  λ•Œ $10, $20, $50 이 μžˆλ‹€λ©΄ λ‹€μŒκ³Ό 같이 4 κ°€μ§€ λ°©λ²•μœΌλ‘œ $50을 ν›”μΉ  수 μžˆμŠ΅λ‹ˆλ‹€.

  • $50 ν•œ μž₯을 ν›”μΉœλ‹€
  • $20 두 μž₯, $10 ν•œ μž₯을 ν›”μΉœλ‹€
  • $20 ν•œ μž₯, $10 μ„Έ μž₯을 ν›”μΉœλ‹€
  • $10 λ‹€μ„― μž₯을 ν›”μΉœλ‹€

ν›”μΉ˜κ³  싢은 target κΈˆμ•‘κ³Ό κΈˆκ³ μ— μžˆλŠ” 돈의 μ’…λ₯˜ type 을 μž…λ ₯λ°›μ•„, μ‘°μ§€κ°€ target 을 ν›”μΉ  수 μžˆλŠ” λ°©λ²•μ˜ 수λ₯Ό λ¦¬ν„΄ν•˜μ„Έμš”.
 

✏️  풀이

⁇ 레퍼런슀 μ½”λ“œ 봐도 λͺ¨λ₯΄κ² λ‹€.
경우의 수λ₯Ό κ΅¬ν•˜μ§€ μ•Šμ•˜λŠ”λ° μ–΄λ–»κ²Œ 배열에 μ €μž₯λ˜μžˆλŠ”κ±°μ§€..

function ocean(target, type) {
  // bag μ΄λΌλŠ” 배열에 κΈˆμ•‘μ„ λ§Œλ“€ 수 μžˆλŠ” 경우의 수λ₯Ό 기둝
  // 각 인덱슀 no# = λ§Œλ“œλ €λŠ” κΈˆμ•‘ 을 의미
  // ex) target = 5, type = [1, 2, 5] λ©΄
  // bag[3] = 2  => 3원을 λ§Œλ“œλŠ” 경우의 수 = 1만 μ‚¬μš© & 1,2 ν•¨κ»˜ μ‚¬μš© (1*3, 1 + 2)
  // bag[4] = 3  => 4원을 λ§Œλ“œλŠ” 경우의 수 = 1만 μ‚¬μš© & 1,2 ν•¨κ»˜ μ‚¬μš© (1*4, 1*2 + 2, 2*2)
  // bag[5] = 4  => 5원을 λ§Œλ“œλŠ” 경우의 수 = 1만 μ‚¬μš© & 1,2 ν•¨κ»˜ μ‚¬μš© & 1, 2, 5 ν•¨κ»˜ μ‚¬μš© (1*5 , 1*3 + 2, 1 + 2*2, 5*1)
  // 0 을 λ§Œλ“€ 수 μžˆλŠ” κ²½μš°λŠ” 아무것도 μ„ νƒν•˜μ§€ μ•ŠμœΌλ©΄ 되기 λ•Œλ¬Έμ— bag[0] = 1 둜 μ΄ˆκΈ°κ°’ μ„€μ •
  let bag = [1];

  // 인덱슀 no# = λ§Œλ“œλ €λŠ” κΈˆμ•‘ 이기 λ•Œλ¬Έμ—
  // bag 을 target κΈˆμ•‘λ§ŒνΌμ˜ 길이λ₯Ό κ°€μ§„ 배열을 λ§Œλ“€μ–΄ μ£Όκ³ ,
  // 경우의 수λ₯Ό μ €μž₯ν•˜κΈ° μœ„ν•΄ μ΄ˆκΈ°κ°’μ€ λͺ¨λ‘ 0으둜 λ§Œλ“€μ–΄ μ€€λ‹€
  for(let i = 1; i <= target; i++)
    bag[i] = 0;
  // 돈의 μ’…λ₯˜κ°€ λ‹΄κ²¨μžˆλŠ” 배열을 순차적으둜 탐색   
  for(let i = 0; i < type.length; i++) {
  // target κΈˆμ•‘κΉŒμ§€ 순차적으둜 1μ”© μ¦κ°€ν•˜λ©΄μ„œ    
    for(let j = 1; j <= target; j++)
  // bag의 μΈλ±μŠ€κ°€ type[i] 보닀 큰 κ΅¬κ°„λ§Œ
  // (μž‘μ€ ꡬ간은 type[i]둜 λ§Œλ“€ 수 μ—†λŠ” κΈˆμ•‘μ΄κΈ° λ•Œλ¬Έμ— 탐색할 ν•„μš”κ°€ μ—†λ‹€)    
      if(type[i] <= j)
  // κΈ°μ‘΄ 경우의 μˆ˜μ— type[i]λ₯Ό λΊ€ κΈˆμ•‘μ„ λ§Œλ“€ 수 μžˆλŠ” 경우의 수λ₯Ό 더해쀀닀       
        bag[j] += bag[j-type[i]];
        console.log(bag)
  }
  // bag 의 target μΈλ±μŠ€μ— target κΈˆμ•‘μ„ ν›”μΉ  수 μžˆλŠ” 경우의 μˆ˜κ°€ μŒ“μ΄λ―€λ‘œ
  // ν•΄λ‹Ή 값을 리턴해 μ€€λ‹€
  return bag[target];
}

πŸ“Œ  문제

κ°€μœ„λ°”μœ„λ³΄ κ²Œμž„μ€ 2인 μ΄μƒμ˜ μ‚¬λžŒμ΄ λ™μ‹œμ— 'κ°€μœ„, λ°”μœ„, 보'λ₯Ό μ™ΈμΉ˜κ³  λ™μ‹œμ— κ°€μœ„, λ°”μœ„ λ˜λŠ” 보 μ€‘μ—μ„œ ν•œ κ°€μ§€λ₯Ό μ˜λ―Έν•˜λŠ” 손 λͺ¨μ–‘을 λ‚΄λ°€μ–΄ μŠΉλΆ€λ₯Ό κ²°μ •μ§“λŠ” κ²Œμž„μž…λ‹ˆλ‹€. μ„Έ 판의 κ°€μœ„λ°”μœ„λ³΄ κ²Œμž„μ„ ν•  경우, ν•œ μ‚¬λžŒμ€ μ„Έ 번의 선택(예. κ°€μœ„, κ°€μœ„, 보)을 ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ„Έ 번의 μ„ νƒμœΌλ‘œ κ°€λŠ₯ν•œ λͺ¨λ“  경우의 수λ₯Ό κ΅¬ν•˜λŠ” ν•¨μˆ˜λ₯Ό μž‘μ„±ν•©λ‹ˆλ‹€.
 

✏️  풀이

πŸ’‘ μ€‘λ³΅μˆœμ—΄

function rockPaperScissors (n=3) {
  const result = [];
  const arr = [['rock'], ['paper'], ['scissors']];
  if(n===1) return [['rock'], ['paper'], ['scissors']];
  // μž¬κ·€κ°€ 끝날 수 μžˆλŠ” 기쀀을 λ§Œλ“€μ–΄μ£Όκ³ 

  let prev = rockPaperScissors(n - 1);
  // ν•˜λ‚˜λŠ” λ½‘μ•˜μœΌλ‹ˆ λ§Œμ•½ n=3이라면 2개만 더 λ½‘μœΌλ©΄ λœλ‹€.
  
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < prev.length; j++) {
      result.push([...arr[i], ...prev[j]]);
      // 뽑아둔 μ• λž‘ 합쳐쀀닀
    }
  }

  return result;
};

πŸ“Œ  문제

κ°œμ—… 이래둜 항상 승승μž₯κ΅¬ν•˜λŠ” '승승μž₯ꡬ μΉ˜ν‚¨μ§‘'의 비결은 μ†ŒμŠ€μ— μžˆλ‹€. μˆ˜λ§Žμ€ 타사 λΈŒλžœλ“œ μΉ˜ν‚¨μ§‘λ“€μ΄ 승승μž₯ꡬ μΉ˜ν‚¨μ§‘μ˜ μ†ŒμŠ€ 비결을 μ•Œμ•„λ‚΄λ €κ³  ν–ˆμœΌλ‚˜ 빈번히 ν¬κΈ°ν–ˆλ‹€. κ·Έ μ΄μœ λŠ” 5λŒ€μ§Έ λ‚΄λ €μ˜€λŠ” 'λΉ„λ°€μ˜ 승승μž₯ꡬ μΉ˜ν‚¨ μ†ŒμŠ€ λΉ„μœ¨ λ ˆμ‹œν”Ό'λŠ” 70μ–΅ 인ꡬ 쀑 사μž₯λ‹˜λ§Œ μ•Œκ³  있기 λ•Œλ¬Έμ΄λ‹€. 졜근, λˆ„λ¦¬κΎΌ μ‚¬μ΄μ—μ„œ 이 λ ˆμ‹œν”Όμ˜ 일뢀뢄을 λ°œμ·Œν–ˆλ‹€λŠ” μ†Œλ¬Έμ„ λ“£κ²Œ λ˜μ—ˆλ‹€. κ·Έ μ†Œλ¬Έμ€ λ‹€μŒκ³Ό κ°™λ‹€.

  1. N κ°€μ§€μ˜ 재료 쀑에 단 M κ°€μ§€λ§Œμ„ μ‚¬μš©ν•˜μ—¬ μ‘°ν•©ν•œ λͺ¨λ“  경우의 수 쀑 ν•˜λ‚˜μ΄λ‹€.
  2. μž¬λ£ŒλŠ” 0κ³Ό 1둜만 이루어진 숫자둜 μ•”ν˜Έν™”κ°€ λ˜μ–΄ 있고, 항상 1둜 μ‹œμž‘ν•˜λ©° λ³΅ν˜Έν™”λ₯Ό ν•  수 μ—†λ‹€.
    1. 단, 0이 3개 이상인 μž¬λ£ŒλŠ” μƒν•œ 재료이기 λ•Œλ¬Έμ— μ œμ™Έν•œλ‹€.
  3. 재료의 μˆœμ„œμ— 따라 맛이 달라지기 λ•Œλ¬Έμ—, 재료λ₯Ό λ„£λŠ” μˆœμ„œκ°€ λ‹€λ₯΄λ‹€λ©΄ λ‹€λ₯Έ λ ˆμ‹œν”Όμ΄λ‹€.

이 μ†Œλ¬Έμ„ μ°Έκ³ ν•˜μ—¬ 'λΉ„λ°€μ˜ 승승μž₯ꡬ μΉ˜ν‚¨ μ†ŒμŠ€'κ°€ 될 수 μžˆλŠ” 경우의 수λ₯Ό λͺ¨λ‘ λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜λ₯Ό μž‘μ„±ν•˜μ„Έμš”.
 

✏️  풀이

πŸ’‘ μˆœμ—΄

function newChickenRecipe(stuffArr, choiceNum) {
  const answer = [];
  const grad = zeroThree(stuffArr);

    if(choiceNum === 1) return grad.map((item) => [item]);

    grad.forEach((item, idx, origin) => {
      const remain = [...origin.slice(0, idx), ...origin.slice(idx+1)];
      // μ„ νƒν•œ μ›μ†Œ μ œμ™Έν•œ λ‚˜λ¨Έμ§€ => μˆœμ„œ μ‹ κ²½μ¨μ€˜μ•Όν•œλ‹€.
      const rePermutation = newChickenRecipe(remain, choiceNum-1);
      // μ œμ™Έν•œ μ• λ“€ μ€‘μ—μ„œ λ‹€μ‹œ λ½‘λŠ”λ°, μ•„κΉŒ ν•˜λ‚˜ λ½‘μ•˜μœΌλ‹ˆκΉŒ -1ν•΄μ„œ μž¬κ·€ ν˜ΈμΆœν•΄μ£ΌκΈ°
      const result = rePermutation.map((el) => [item, ...el]);
      // μ²˜μŒμ— 뽑아 놓은 μ•  μ—°κ²°ν•΄μ£ΌκΈ°
      answer.push(...result);
    });
    return answer;
  }

function zeroThree(stuffArr){
  // 0이 3개 이상이면 μƒν•œ μŒμ‹μ΄λ―€λ‘œ μ œμ™Έν•΄μ£ΌκΈ°
  let zeroThree = /0{3}/;
  let grad = stuffArr.filter((item) => {
    return zeroThree.test(item) === false;
  });
  return grad;
}

πŸ“Œ  문제

ν‰λ²”ν•œ λΈ”λž™μž­ κ²Œμž„μ—μ„œ μˆ˜μ‹œλ‘œ νŒ¨λ°°ν•˜μž ν₯λ―Έκ°€ λ–¨μ–΄μ§„ 김코딩은 λ°•νƒ€μ§œμ—κ²Œ κ²Œμž„λ£°μ„ λ³€ν˜•ν•˜μ—¬ μƒˆλ‘œμš΄ μΉ΄λ“œ 놀이λ₯Ό ν•΄ λ³Ό 것을 μ œμ•ˆν•©λ‹ˆλ‹€. μƒˆλ‘œμš΄ 룰은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.
 
1. μˆ«μžλ‘œ μ΄λ£¨μ–΄μ§„ μΉ΄λ“œλ₯Ό μ—¬λŸ¬ μž₯ λ°›μŠ΅λ‹ˆλ‹€.
2. 3μž₯μ”© μΉ΄λ“œλ₯Ό κ³ λ₯΄κ³ , 3μž₯에 μ νžŒ μˆ«μžλ“€μ˜ ν•©μ΄ μ†Œμˆ˜μΈμ§€ ν™•μΈν•©λ‹ˆλ‹€.
3. λ°›μ•„λ“  μΉ΄λ“œλ‘œ λ§Œλ“€ μˆ˜ μžˆλŠ” μ†Œμˆ˜μ˜ κ°œμˆ˜κ°€ λ§Žμ€ μ‚¬λžŒμ΄ μ΄κΈ°κ²Œ λ©λ‹ˆλ‹€.
 
예둜, [1, 2, 3, 4]λΌλŠ” μΉ΄λ“œλ₯Ό λ°›μ•˜μ„ λ•Œ λ§Œλ“€ 수 μžˆλŠ” μˆ«μžλŠ” 6, 7, 8, 9이고, μ†Œμˆ˜λŠ” 7 ν•˜λ‚˜μ΄κΈ° λ•Œλ¬Έμ— κ°€μ§€κ³  μžˆλŠ” μ†Œμˆ˜μ˜ κ°œμˆ˜λŠ” 1κ°œμž…λ‹ˆλ‹€. [2, 3, 4, 8, 13]λΌλŠ” μΉ΄λ“œλ₯Ό λ°›μ•˜μ„ λ•Œ λ§Œλ“€ 수 μžˆλŠ” μˆ«μžλŠ” 9, 13, 18, 14, 19, 23, 15, 20, 24, 25이고, μ†Œμˆ˜λŠ” 13, 19, 23 총 3개이기 λ•Œλ¬Έμ— κ°€μ§€κ³  μžˆλŠ” μ†Œμˆ˜μ˜ κ°œμˆ˜λŠ” 3κ°œμž…λ‹ˆλ‹€.
 
κ²Œμž„μ„ μ§„ν–‰ν•˜κΈ° 전에 μ†Œμˆ˜μ— λŒ€ν•΄ μ•„λ¬΄λŸ° 지식이 μ—†λŠ” λ°•νƒ€μ§œλŠ” κ²Œμž„μ„ λ©°μΉ  미룬 λ’€, κ²Œμž„μ˜ 룰을 λ”°λ₯΄λŠ” ν•¨μˆ˜λ₯Ό λ§Œλ“€κΈ°λ‘œ ν–ˆμŠ΅λ‹ˆλ‹€. μ†Œμˆ˜μ— μ•½ν•œ λ°•νƒ€μ§œλ₯Ό 도와 μ—¬λŸ¬ μž₯의 μΉ΄λ“œ 쀑 μ„Έ μž₯μ”© μ‘°ν•©ν•΄ μ†Œμˆ˜κ°€ λ˜λŠ” 경우의 수λ₯Ό λ¦¬ν„΄ν•˜λŠ” ν•¨μˆ˜λ₯Ό μ™„μ„±ν•΄ μ£Όμ„Έμš”.
 

✏️  풀이

πŸ’‘ μ‘°ν•© + μ†Œμˆ˜ κ΅¬ν•˜κΈ°

function boringBlackjack(cards) {
  let answer = 0;
  const permutation = combinations(cards, 3);
  // μ‘°ν•©μœΌλ‘œ μΉ΄λ“œ 3μž₯ 뽑아주기

  permutation.map((item) => { 
  // μ‘°ν•© κ°€μ Έμ™€μ„œ 각 μ‘°ν•©μ˜ ν•© κ΅¬ν•˜κ³ 
    let sum = 0;
    for(let i=0; i<item.length; i++){
      sum += item[i];
    }

    if(isPrime(sum)) answer++;
    // κ·Έ 합이 μ†Œμˆ˜μΈμ§€ 확인
  })
  return answer;
}

function combinations(arr, choiceNum){
// μ‘°ν•© ν•¨μˆ˜
  const answer = [];

    if(choiceNum === 1) return arr.map((item) => [item]);

    arr.forEach((item, idx, origin) => {
      const remain = [ ...origin.slice(idx+1)];
      // 쑰합은 μˆœμ„œ 상관 μ—†μœΌλ‹ˆκΉŒ μˆœμ—΄κ³ΌλŠ” λ‹€λ₯΄κ²Œ ν•΄μ€˜μ•Όν•œλ‹€.
      const rePermutation = combinations(remain, choiceNum-1);
      // μ œμ™Έν•œ μ• λ“€ μ€‘μ—μ„œ λ‹€μ‹œ λ½‘λŠ”λ°, μ•„κΉŒ ν•˜λ‚˜ λ½‘μ•˜μœΌλ‹ˆκΉŒ -1ν•΄μ„œ μž¬κ·€ ν˜ΈμΆœν•΄μ£ΌκΈ°
      const result = rePermutation.map((el) => [item, ...el]);
      // μ²˜μŒμ— 뽑아 놓은 μ•  μ—°κ²°ν•΄μ£ΌκΈ°
      answer.push(...result);
    });
    return answer;
}

function isPrime(num){
// μ†Œμˆ˜ 확인 ν•¨μˆ˜
  if(num === 2) return true;
  if(num === 1) return false;

  for(let i=2; i<=Math.ceil(Math.sqrt(num)); i++){
    if(num%i === 0) {
      return false;
    }
  }

  return true;
}

πŸ“Œ  문제

김코딩은 λͺ‡ λ…„μ˜ ν•΄μ™Έ 좜μž₯ 끝에 본가에 λ‚΄λ €μ™”μŠ΅λ‹ˆλ‹€. μ˜€λžœλ§Œμ— λ³΄λŠ” κΉ€μ½”λ”©μ˜ 얼꡴에 λ°˜κ°€μ› λ˜ λΆ€λͺ¨λ‹˜μ€ 상닀리가 λΆ€λŸ¬μ§ˆ μ •λ„λ‘œ μŒμ‹μ„ λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€. κ°λ™μ˜ μž¬νšŒλ„ μž μ‹œ, μ˜μžμ— 앉아 식사λ₯Ό ν•˜λ €λ˜ 김코딩은 무엇뢀터 λ¨Ήμ–΄μ•Ό 될지 κΉŠμ€ 생각에 λΉ μ‘ŒμŠ΅λ‹ˆλ‹€. μ •μ„±μŠ€λŸ½κ²Œ μ°¨λ € μ£Όμ‹  만큼, μ΅œλŒ€ν•œ λ§Žμ€ λ°©λ²•μœΌλ‘œ λ‹€μ–‘ν•˜κ²Œ λ¨Ήκ³  μ‹Άμ—ˆκΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.
λ°₯은 ν•œ 가지이며 λ°˜μ°¬μ€ λ‹€μˆ˜μΌ λ•Œ, λ°₯κ³Ό ν•¨κ»˜ 먹을 수 μžˆλŠ” 반찬의 λͺ¨λ“  경우의 수λ₯Ό 배열에 λ‹΄μ•„ λ¦¬ν„΄ν•˜μ„Έμš”.
 

✏️  풀이

πŸ’‘ λ©±μ§‘ν•©

function missHouseMeal(sideDishes) {
  const result = [];

  function recursion(subset, start) {
    subset.sort();
    // μ‚¬μ „μˆœμœΌλ‘œ μ •λ ¬
    result.push(subset);

    for(let i=start; i<sideDishes.length; i++){
      recursion([...subset, sideDishes[i]], i+1);
      // λΆ€λΆ„ 집합을 forλ¬Έ λŒλ©΄μ„œ 계속 λŠ˜λ €κ°„λ‹€.
    }
  }
  recursion([], 0);

  result.sort();
  return result;
}