Algorithm

[Algorithm] μŠ€ν‹°μ»€ λͺ¨μœΌκΈ°2

ghkdu2 2023. 3. 3. 10:20

πŸ“‹ 문제 

N개의 μŠ€ν‹°μ»€κ°€ μ›ν˜•μœΌλ‘œ μ—°κ²°λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. λ‹€μŒ 그림은 N = 8인 경우의 μ˜ˆμ‹œμž…λ‹ˆλ‹€.


μ›ν˜•μœΌλ‘œ μ—°κ²°λœ μŠ€ν‹°μ»€μ—μ„œ λͺ‡ μž₯의 μŠ€ν‹°μ»€λ₯Ό λœ―μ–΄λ‚΄μ–΄ λœ―μ–΄λ‚Έ μŠ€ν‹°μ»€μ— 적힌 숫자의 합이 μ΅œλŒ€κ°€ λ˜λ„λ‘ ν•˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€. 단 μŠ€ν‹°μ»€ ν•œ μž₯을 λœ―μ–΄λ‚΄λ©΄ μ–‘μͺ½μœΌλ‘œ μΈμ ‘ν•΄μžˆλŠ” μŠ€ν‹°μ»€λŠ” μ°’μ–΄μ Έμ„œ μ‚¬μš©ν•  수 μ—†κ²Œ λ©λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄ μœ„ κ·Έλ¦Όμ—μ„œ 14κ°€ 적힌 μŠ€ν‹°μ»€λ₯Ό 뜯으면 μΈμ ‘ν•΄μžˆλŠ” 10, 6이 적힌 μŠ€ν‹°μ»€λŠ” μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€. μŠ€ν‹°μ»€μ— 적힌 μˆ«μžκ°€ λ°°μ—΄ ν˜•νƒœλ‘œ μ£Όμ–΄μ§ˆ λ•Œ, μŠ€ν‹°μ»€λ₯Ό λœ―μ–΄λ‚΄μ–΄ 얻을 수 μžˆλŠ” 숫자의 ν•©μ˜ μ΅œλŒ“κ°’μ„ return ν•˜λŠ” solution ν•¨μˆ˜λ₯Ό μ™„μ„±ν•΄ μ£Όμ„Έμš”. μ›ν˜•μ˜ μŠ€ν‹°μ»€ λͺ¨μ–‘을 μœ„ν•΄ λ°°μ—΄μ˜ 첫 번째 μ›μ†Œμ™€ λ§ˆμ§€λ§‰ μ›μ†Œκ°€ μ„œλ‘œ μ—°κ²°λ˜μ–΄ μžˆλ‹€κ³  κ°„μ£Όν•©λ‹ˆλ‹€.

 

μ œν•œ 사항

  • stickerλŠ” μ›ν˜•μœΌλ‘œ μ—°κ²°λœ μŠ€ν‹°μ»€μ˜ 각 칸에 적힌 μˆ«μžκ°€ μˆœμ„œλŒ€λ‘œ λ“€μ–΄μžˆλŠ” λ°°μ—΄λ‘œ, 길이(N)λŠ” 1 이상 100,000 μ΄ν•˜μž…λ‹ˆλ‹€.
  • sticker의 각 μ›μ†ŒλŠ” μŠ€ν‹°μ»€μ˜ 각 칸에 적힌 숫자이며, 각 칸에 적힌 μˆ«μžλŠ” 1 이상 100 μ΄ν•˜μ˜ μžμ—°μˆ˜μž…λ‹ˆλ‹€.
  • μ›ν˜•μ˜ μŠ€ν‹°μ»€ λͺ¨μ–‘을 μœ„ν•΄ sticker λ°°μ—΄μ˜ 첫 번째 μ›μ†Œμ™€ λ§ˆμ§€λ§‰ μ›μ†Œκ°€ μ„œλ‘œ μ—°κ²°λ˜μ–΄μžˆλ‹€κ³  κ°„μ£Όν•©λ‹ˆλ‹€.

 

μž…μΆœλ ₯ 예

[14, 6, 5, 11, 3, 9, 2, 10] 36
[1, 3, 2, 5, 4] 8

 

 

✏️ 풀이

고민을 정말 많이 ν–ˆλ‹€. μ²˜μŒμ—λŠ” λͺ¨λ“  경우λ₯Ό νƒμƒ‰ν•΄μ•Όν•˜λ‚˜? DFS둜 λŒλ €λ΄μ•Όν•˜λ‚˜ μͺ½μœΌλ‘œ μ ‘κ·Όν–ˆμ§€λ§Œ sticker λ°°μ—΄μ˜ 길이가 100,000이 λœλ‹€λ©΄ λ‹Ήμ—°ν•˜κ²Œ μ‹œκ°„μ΄ˆκ³Όλ‘œ μ΄μ–΄μ§ˆ 것 κ°™μ•„ μ‹œλ„ν•˜μ§€ μ•Šμ•˜λ‹€. κ²°κ΅­ DP둜 μ ‘κ·Όν–ˆλ‹€. ν•˜λ‚˜μ˜ 슀트컀λ₯Ό 뜯으면 μ–‘ μ˜†μ˜ μŠ€ν‹°μ»€λ₯Ό λœ―μ§€ λͺ»ν•˜κ²Œ λ˜μ–΄ 이번 μŠ€ν‹°μ»€λ₯Ό λœ―λŠ” 경우(dp[i-2] + sticker[i])와 μ•ˆ λœ―λŠ” 경우(dp[i])λ₯Ό λΉ„κ΅ν–ˆλ‹€. λ°°μ—΄μ˜ 길이만큼 μ§„ν–‰ν•˜λ©΄ λ§ˆμ§€λ§‰ μš”μ†Œκ°€ μ΅œλŒ€κ°’μ΄ λœλ‹€.

 

dp[i] = i + 1 λ²ˆμ§ΈκΉŒμ§€ μ§„ν–‰ν–ˆμ„ λ•Œμ˜ μ΅œλŒ€κ°’

 

μ²˜μŒμ—λŠ” 1 * n 길이의 λ°°μ—΄λ‘œ μ ‘κ·Όν–ˆλŠ”λ° 첫 번째 μŠ€ν‹°μ»€λ₯Ό 뜯고 μ•ˆλœ―κ³ μ— 따라 차이가 λ‚  수 밖에 μ—†λ‹€λŠ” 사싀을 μ•Œκ²Œ λ˜μ—ˆλ‹€. i-2의 μš”μ†Œμ™€ λΉ„κ΅ν•˜κΈ° μœ„ν•΄ μˆœνšŒν• λ•Œ i의 μ΄ˆκΈ°κ°’μ΄ 2둜 μ‹œμž‘ν–ˆλŠ”λ° μ΄ˆκΈ°κ°’ μ…‹νŒ…ν•  λ•Œ 값을 λ‹€λ₯΄κ²Œ λ„£μ–΄μ€˜μ•Ό ν•œλ‹€. 첫 번째λ₯Ό λœ―μ—ˆμ„ 경우 dp[0], dp[1]은 μ΅œλŒ€κ°’μ΄ sticker[0]이 되고, λœ―μ§€ μ•Šμ•˜μ„ 경우 dp[0]은 0, dp[1](두 번째λ₯Ό λœ―μ€ μ΅œλŒ€κ°’)은 sticker[1]이 되기 λ•Œλ¬Έμ΄λ‹€. λ”°λΌμ„œ dp배열을 2 * n으둜 μ…‹νŒ…ν•˜κ³  λ§ˆμ§€λ§‰μ— λΉ„κ΅ν–ˆλ‹€.

 

μΆ”κ°€μ μœΌλ‘œ 반볡문 λ‚΄μ—μ„œ Math.maxλ₯Ό μ‚¬μš©ν–ˆμ—ˆλŠ”λ° νš¨μœ¨μ„±ν…ŒμŠ€νŠΈμ—μ„œ 2개 μΌ€μ΄μŠ€κ°€ μ‹œκ°„μ΄ˆκ³Όκ°€ 났닀. μ‚Όν•­μ—°μ‚°μžλ‘œ λ³€κ²½ν•˜λ‹ˆ 해결됬닀.(생각보닀 Math.max λ©”μ„œλ“œκ°€ 느린 것 κ°™λ‹€.)

 

⌨️ μ½”λ“œ

function solution(sticker) {
  var answer = 0;

  const len = sticker.length;
  if (len <= 1) return sticker[0];

  const dp = [...Array(2)].map(_ => new Array(len).fill(0));

  dp[0][0] = sticker[0];
  dp[0][1] = sticker[0];
  dp[1][1] = sticker[1];

  for (let i = 2; i < len; i++) {
    dp[0][i] = dp[0][i - 2] + sticker[i] > dp[0][i - 1] ? dp[0][i - 2] + sticker[i] : dp[0][i - 1];
    dp[1][i] = dp[1][i - 2] + sticker[i] > dp[1][i - 1] ? dp[1][i - 2] + sticker[i] : dp[1][i - 1];
  }

  answer = Math.max(dp[0][len - 2], dp[1][len - 1]);

  return answer;
}