Description
You are given a 0-indexed string s and a dictionary of words dictionary. You have to break s into one or more non-overlapping substrings such that each substring is present in dictionary. There may be some extra characters in s which are not present in any of the substrings.
Return the minimum number of extra characters left over if you break up s optimally.
Example 1:
Input: s = "leetscode", dictionary = ["leet","code","leetcode"]
Output: 1
Explanation: We can break s in two substrings: "leet" from index 0 to 3 and "code" from index 5 to 8. There is only 1 unused character (at index 4), so we return 1.
Example 2:
Input: s = "sayhelloworld", dictionary = ["hello","world"]
Output: 3
Explanation: We can break s in two substrings: "hello" from index 3 to 7 and "world" from index 8 to 12. The characters at indices 0, 1, 2 are not used in any substring and thus are considered as extra characters. Hence, we return 3.
Constraints:
1 <= s.length <= 50
1 <= dictionary.length <= 50
1 <= dictionary[i].length <= 50
dictionary[i] and s consists of only lowercase English letters
dictionary contains distinct words
Solution
Recursive
If we start with i
, then f(i) = min(1 + f(i + 1), 2 + f(i + 2), ...)
if s[i+1]
not in dictionary. Use memory to speed up time.
Time complexity:
o
(
n
!
)
o(n!)
o(n!)
Space complexity:
o
(
n
)
o(n)
o(n)
DP
Use dp[i]
to denote the answer for s[0:i]
, then transformation equation is:
d
p
[
i
]
=
min
(
d
p
[
i
−
k
]
+
{
k
,
if s[i-k:i] not in dictionary
0
,
else
)
,
∀
k
∈
[
1
,
i
]
dp[i] = \min(dp[i - k] + \begin{cases}k, \;\; \text{if s[i-k:i] not in dictionary} \\ 0, \;\; \text{else}\end{cases}), \;\; \forall k \in [1, i]
dp[i]=min(dp[i−k]+{k,if s[i-k:i] not in dictionary0,else),∀k∈[1,i]
Time complexity:
o
(
n
2
)
o(n^2)
o(n2)
Space complexity:
o
(
n
)
o(n)
o(n)
Code
Recursive
class Solution:
def minExtraChar(self, s: str, dictionary: List[str]) -> int:
memo = {len(s): 0}
def helper(s_index: int) -> int:
if s_index in memo:
return memo[s_index]
res = []
for i in range(s_index, len(s)):
cur_prefix = s[s_index: i + 1]
if cur_prefix not in dictionary:
res.append(len(cur_prefix) + helper(i + 1))
else:
res.append(helper(i + 1))
memo[s_index] = min(res)
return memo[s_index]
return helper(0)
DP
class Solution:
def minExtraChar(self, s: str, dictionary: List[str]) -> int:
dp = [i for i in range(len(s) + 1)]
for i in range(1, len(s) + 1):
for k in range(1, i + 1):
prefix = s[i - k: i]
dp[i] = min(dp[i], dp[i - k] + (k if prefix not in dictionary else 0))
return dp[-1]