String Compression II

hard string dp

Problem

Given a string s and integer k, delete at most k characters so that the run-length encoded form of the resulting string is as short as possible. Return that minimum length.

Inputs = "aaabcccd", k = 2
Output4
Delete 'b' and 'd' to get "aaaccc" → "a3c3", length 4.

from functools import lru_cache

def get_length_of_optimal_compression(s, k):
    n = len(s)
    def enc(x):
        if x == 1: return 1
        if x < 10: return 2
        if x < 100: return 3
        return 4
    @lru_cache(maxsize=None)
    def dp(i, k):
        if k < 0: return float('inf')
        if i == n: return 0
        best = dp(i + 1, k - 1)  # delete s[i]
        cnt, deleted = 0, 0
        for j in range(i, n):
            if s[j] == s[i]: cnt += 1
            else: deleted += 1
            if deleted > k: break
            best = min(best, enc(cnt) + dp(j + 1, k - deleted))
        return best
    return dp(0, k)
function getLengthOfOptimalCompression(s, k) {
  const n = s.length;
  const memo = new Map();
  function enc(x) { return x === 1 ? 1 : x < 10 ? 2 : x < 100 ? 3 : 4; }
  function dp(i, k) {
    if (k < 0) return Infinity;
    if (i === n) return 0;
    const key = i * 110 + k;
    if (memo.has(key)) return memo.get(key);
    let best = dp(i + 1, k - 1);
    let cnt = 0, del = 0;
    for (let j = i; j < n; j++) {
      if (s[j] === s[i]) cnt++; else del++;
      if (del > k) break;
      best = Math.min(best, enc(cnt) + dp(j + 1, k - del));
    }
    memo.set(key, best);
    return best;
  }
  return dp(0, k);
}
class Solution {
    int n; String s; int[][] memo;
    int enc(int x) { return x == 1 ? 1 : x < 10 ? 2 : x < 100 ? 3 : 4; }
    public int getLengthOfOptimalCompression(String s, int k) {
        this.s = s; this.n = s.length();
        memo = new int[n + 1][k + 1];
        for (int[] row : memo) Arrays.fill(row, -1);
        return dp(0, k);
    }
    int dp(int i, int k) {
        if (k < 0) return Integer.MAX_VALUE / 2;
        if (i == n) return 0;
        if (memo[i][k] != -1) return memo[i][k];
        int best = dp(i + 1, k - 1);
        int cnt = 0, del = 0;
        for (int j = i; j < n; j++) {
            if (s.charAt(j) == s.charAt(i)) cnt++; else del++;
            if (del > k) break;
            best = Math.min(best, enc(cnt) + dp(j + 1, k - del));
        }
        return memo[i][k] = best;
    }
}
int memo[101][101];
string ss;
int enc(int x) { return x == 1 ? 1 : x < 10 ? 2 : x < 100 ? 3 : 4; }
int dp(int i, int k) {
    int n = ss.size();
    if (k < 0) return 1e9;
    if (i == n) return 0;
    if (memo[i][k] != -1) return memo[i][k];
    int best = dp(i + 1, k - 1);
    int cnt = 0, del = 0;
    for (int j = i; j < n; j++) {
        if (ss[j] == ss[i]) cnt++; else del++;
        if (del > k) break;
        best = min(best, enc(cnt) + dp(j + 1, k - del));
    }
    return memo[i][k] = best;
}
int getLengthOfOptimalCompression(string s, int k) {
    ss = s;
    memset(memo, -1, sizeof memo);
    return dp(0, k);
}
Time: O(n² · k) Space: O(n · k)