Skip to content
RSS feed tkhwang on GitHub tkhwang on Twitter

πŸ€– leetcode 1312. Minimum Insertion Steps to Make a String Palindrome | hard | dynamic-programming | javascript

πŸ—’οΈ Problems

Minimum Insertion Steps to Make a String Palindrome - LeetCode

Given a string s. In one step you can insert any character at any index of the string.

Return the minimum number of steps to make s palindrome.

A Palindrome String is one that reads the same backward as well as forward.
Input: s = "zzazz"
Output: 0
Explanation: The string "zzazz" is already palindrome we do not need any insertions.

✨ Idea

  • dp[i][j] : s[i,...,j] substring 을 palindrome λ§Œλ“€κΈ° μœ„ν•΄μ„œ ν•„μš”ν•œ μ΅œμ†Œ insertion 횟수.
    • μ΅œμ’… λ‹΅ : dp[0][N-1]
  • basecase : i, jκ°€ λ™μΌν•œ 경우인 dp[i][j] 의 κ²½μš°μ—λŠ” 단일 μΊλ¦­ν„°μ΄λ―€λ‘œ 항상 λ™μΌν•˜λ―€λ‘œ insertion νšŸμˆ˜λŠ” 0.
  • μƒνƒœ 전이 방정식: s[i] 와 s[j] λΉ„κ΅ν•˜μ—¬
    • 동일할 λ•Œ : 맨 μ™ΈλΆ€κ°€ λ™μΌν•˜λ―€λ‘œ λ‚΄λΆ€ dp[i+1][j-1] λ³€κ²½νšŸμˆ˜μ™€ 동일함.
    • λ‹€λ₯Ό λ•Œ : ν•œμͺ½λ§Œ ν¬ν•¨ν•œ κ²½μš°μ—μ„œ ν•œ 번 insertion ν•œ 것 λΉ„κ΅ν•΄μ„œ minimum

πŸ€ Intuition

DP : κ²°μ •, μƒνƒœ, μƒνƒœ 전이 방정식

  • κ²°μ • : i,j string κ°’μ˜ 일치 유무
  • μƒνƒœ : dp[i][j] λŠ” s[i,...,j] 의 insertion을 ν†΅ν•œ palindrome λ§Œλ“€ 수 μžˆλŠ” μ΅œμ†Œκ°’.
  • μƒνƒœ 전이 방정식
if (s[i] === s[j]) {
  dp[i][j] = dp[i + 1][j - 1];
} else {
  dp[i][j] = Math.min(1 + dp[i + 1][j], 1 + dp[i][j - 1]);
}

πŸ•ΈοΈ πŸ’‘ dynamic programming μ—μ„œ 순회 λ°©ν–₯의 결정은 μ–΄λ–»κ²Œ ?

Dynamic programming 문제λ₯Ό 보면 μ–΄λ–¨λ•ŒλŠ” 0 -> N 으둜 순회λ₯Ό ν•˜κ³ , μ–΄λ–¨λ•ŒλŠ” N ->0 으둜 μˆœνšŒν•˜λŠ” λ“± λ‹€μ–‘ν•˜μ˜€λŠ”λ° μ•„λž˜ λ‚΄μš©μ„ μ•Œκ²Œ λ˜μ–΄ μ •λ¦¬ν•΄λ΄…λ‹ˆλ‹€.

μƒνƒœ 전이 방정식이 계산이 되기 μœ„ν•΄μ„œλŠ” λ‹€μŒμ„ λ§Œμ‘±ν•΄μ•Ό ν•œλ‹€.

  • μƒμœ„ 문제 dp[i][j] 계산을 μœ„ν•˜μ—¬ 이미 κ³„μ‚°λœ ν•˜μœ„ 문제의 κ²°κ³Όλ₯Ό μ°Έμ‘°ν•˜κ²Œ λ©λ‹ˆλ‹€.
    • 이전 κ°’ dp[i-1][j-1] 을 μ°Έμ‘°ν•˜κΈ°λ„ ν•˜κ³ 
    • palindrome의 κ²½μš°μ—λŠ” λ‚΄λΆ€ string 을 κ²°κ³Όλ₯Ό μ°Έμ‘°ν•΄μ•Όν•˜λ―€λ‘œ dp[i+1][j-1] 값을 참쑰해야함.
  • μƒνƒœ 전이 방정식 계산 맨 λ§ˆμ§€λ§‰μ— μ΅œμ’… κ²°κ³Όκ°€ λ„μΆœλ˜μ–΄ 함.
    • μƒνƒœμ˜ μ •μ˜μ— λ”°λΌμ„œ μ΅œμ’… 값이 달라짐.
    • μ–΄λ–€ κ²½μš°μ—λŠ” dp[N-1][N-1]
    • 이번 κ²½μš°μ—λŠ” string[0, N-1] μ²˜μŒλΆ€ν„° λκΉŒμ§€ κ΅¬μ„±λœ 경우의 μ΅œμ†Œ insertion νšŸμˆ˜κ°€ ν•„μš”ν•˜λ―€λ‘œ μ΅œμ’… 값은 dp[0][N-1]

μ΄λ ‡κ²Œ μƒνƒœ 전이 방정식 계산 κ³Όμ •μ—μ„œ 이전 값이 계산이 λ˜μ–΄μ•Ό ν•˜κ³ , κ·Έ κ³Όμ •μ˜ λ§ˆμ§€λ§‰μ— μ΅œμ’… 닡이 λ„μΆœλ˜λ„λ‘ 순회 λ°©ν–₯을 κ²°μ • ν•©λ‹ˆλ‹€.

이번 문제의 경우

  • basecase i,j κ°€ 같은 κ²½μš°μ—λŠ” 0으둜 μ΄ˆκΈ°κ°’.
  • dp[i][j] 계산 μ‹œ λ‹€μŒ μ„Έκ°œμ˜ 값이 ν•„μš”ν•¨.
    • dp[i+1][j-1]
    • dp[i+1][j]
    • dp[i]][j-1]

이 계산을 μœ„ν•΄μ„œλŠ” λ‹€μŒκ³Ό 같이 μ—­λ°©ν–₯으둜 움직이면 κ°€λŠ₯ν•˜λ‹€.

  • row λ₯Ό [N-2, ..., 0]
  • col 을 [row + 1, ..., N-1]
    for (let i = N -2; i >= 0; i -= 1) {
        for (let j = i + 1; j < N; j += 1) {
            ...
        }
    }

πŸ”₯ My Solution

/**
 * @param {string} s
 * @return {number}
 */
var minInsertions = function (s) {
  const N = s.length;

  const dp = Array(N)
    .fill(null)
    .map((_) => Array(N).fill(0));

  for (let i = N - 2; i >= 0; i -= 1) {
    for (let j = i + 1; j < N; j += 1) {
      if (s[i] === s[j]) {
        dp[i][j] = dp[i + 1][j - 1];
      } else {
        dp[i][j] = Math.min(1 + dp[i + 1][j], 1 + dp[i][j - 1]);
      }
    }
  }

  return dp[0][N - 1];
};