Extra Characters in a String

medium trie dynamic programming string

Problem

Given a 0-indexed string s and a dictionary of words, break s into one or more non-overlapping substrings so that each substring appears in the dictionary. Some characters may be left over as extra characters that belong to no substring. Return the minimum number of extra characters if you break up s optimally.

Inputs = "leetscode", dictionary = ["leet","code","leetcode"]
Output1
Take "leet" (indices 0–3) and "code" (indices 5–8). Only index 4 ('s') is unused, so the answer is 1.

def minExtraChar(s, dictionary):
    n = len(s)
    words = set(dictionary)              # acts like a trie membership test
    dp = [0] * (n + 1)                   # dp[i] = min extra in s[i:]
    for i in range(n - 1, -1, -1):
        dp[i] = dp[i + 1] + 1           # option A: s[i] is extra
        for j in range(i + 1, n + 1):
            if s[i:j] in words:         # s[i:j] is a dictionary word
                dp[i] = min(dp[i], dp[j])
    return dp[0]
function minExtraChar(s, dictionary) {
  const n = s.length;
  const words = new Set(dictionary);          // trie membership test
  const dp = new Array(n + 1).fill(0);        // dp[i] = min extra in s[i:]
  for (let i = n - 1; i >= 0; i--) {
    dp[i] = dp[i + 1] + 1;                     // option A: s[i] is extra
    for (let j = i + 1; j <= n; j++) {
      if (words.has(s.slice(i, j)))            // s[i..j) is a word
        dp[i] = Math.min(dp[i], dp[j]);
    }
  }
  return dp[0];
}
int minExtraChar(String s, String[] dictionary) {
    int n = s.length();
    Set<String> words = new HashSet<>(Arrays.asList(dictionary));
    int[] dp = new int[n + 1];                 // dp[i] = min extra in s[i:]
    for (int i = n - 1; i >= 0; i--) {
        dp[i] = dp[i + 1] + 1;                 // option A: s[i] is extra
        for (int j = i + 1; j <= n; j++) {
            if (words.contains(s.substring(i, j)))
                dp[i] = Math.min(dp[i], dp[j]);
        }
    }
    return dp[0];
}
int minExtraChar(string s, vector<string>& dictionary) {
    int n = s.size();
    unordered_set<string> words(dictionary.begin(), dictionary.end());
    vector<int> dp(n + 1, 0);                   // dp[i] = min extra in s[i:]
    for (int i = n - 1; i >= 0; i--) {
        dp[i] = dp[i + 1] + 1;                 // option A: s[i] is extra
        for (int j = i + 1; j <= n; j++) {
            if (words.count(s.substr(i, j - i)))
                dp[i] = min(dp[i], dp[j]);
        }
    }
    return dp[0];
}
Time: O(n² · L) Space: O(n + total dictionary length)