Introduction
In the realm of dynamic programming, the Word Break Problem stands out as an intriguing challenge that often appears in coding interviews. The problem is to decide if a given string can be segmented into a space-separated sequence of one or more dictionary words. Before we dive into the dynamic programming approach, let's set the stage with some examples.
Problem Statement
Given a string s
and a list of strings (a dictionary) wordDict
, you need to determine if s
can be segmented into words found in wordDict
.
Examples
-
Input:
s = "leetcode"
wordDict = ["leet", "code"]
Output:
True
Explanation:
The string "leetcode" can be broken down into "leet" + "code". -
Input:
s = "applepenapple"
wordDict = ["apple", "pen"]
Output:
True
Explanation:
The string can be segmented as "apple" + "pen" + "apple". -
Input:
s = "catsandog"
wordDict = ["cats", "dog", "sand", "and", "cat"]
Output:
False
Explanation:
There is no valid segmentation for the string "catsandog".
Dynamic Programming Approach
Dynamic programming is an efficient way to tackle this problem by breaking it down into simpler subproblems. The idea is to maintain a boolean array dp
where dp[i]
will be True
if the substring s[0:i]
can be segmented into words from wordDict
.
Step-by-Step Explanation
-
Initialization:
Create a boolean arraydp
of sizelen(s) + 1
, initialized toFalse
. Setdp[0] = True
, as an empty string can always be segmented. -
Iterate Through the String:
For each indexi
from1
tolen(s)
, check every indexj
from0
toi - 1
. Ifdp[j]
isTrue
and the substrings[j:i]
exists inwordDict
, setdp[i]
toTrue
. -
Final Result:
The value ofdp[len(s)]
will indicate whether the entire string can be segmented.
Pseudocode
Here's a breakdown of the pseudocode to implement this approach:
def wordBreak(s: str, wordDict: List[str]) -> bool: wordSet = set(wordDict) dp = [False] * (len(s) + 1) dp[0] = True for i in range(1, len(s) + 1): for j in range(i): if dp[j] and s[j:i] in wordSet: dp[i] = True break return dp[len(s)]
Example Walkthrough
Let’s evaluate s = "leetcode"
with wordDict = ["leet", "code"]
:
-
Initialization:
dp = [True, False, False, False, False, False, False, False, False]
-
Index 1:
j = 0
:
dp[0]
isTrue
, but "l" is not inwordDict
.- Move to index 2, not updating
dp[1]
.
-
Index 2:
j = 0
:
dp[0]
isTrue
, but "le" is not inwordDict
.j = 1
:
dp[1]
isFalse
, skip it.- Move to index 3,
dp[2]
remainsFalse
.
-
Index 3:
j = 0
:
"lee" is not inwordDict
.- Apply similar checks until index 4.
- At
i=4
:j=0
: "leet" inwordDict
, sodp[4] = True
.
Following this logic through to i=8
, we find that dp[len(s)]
is True
.
Complexity Analysis
-
Time Complexity:
The time complexity for this approach is O(n^2), where n is the length of the string. This is due to the two nested loops traversing the string. -
Space Complexity:
The space complexity is O(n) for thedp
array.
By employing a dynamic programming solution, you can handle larger strings and dictionaries efficiently, gaining proficiency in this essential problem-solving technique.