Word Break

You are given a string s and a list dictionary[] of words. Your task is to determine whether the string s can be formed by concatenating one or more words from the dictionary[].

Note: From dictionary[], any word can be taken any number of times and in any order.

Examples :

Input: s= "ilike", dictionary[] = ["i", "like", "gfg"]
Output: true Explanation: s can be breakdown as "i like".
Input: s= "ilikegfg", dictionary[] = ["i", "like", "man", "india", "gfg"]
Output: true
Explanation: s can be breakdown as "i like gfg".
Input: s= "ilikemangoes", dictionary[] = ["i", "like", "man", "india", "gfg"]
Output: false
Explanation: s cannot be formed using dictionary[] words.

Constraints:
1 ≤ s.size() ≤ 3000
1 ≤ dictionary.size() ≤ 1000
1 ≤ dictionary[i].size() ≤ 100


Approach 01:

#include <vector>
#include <string>
#include <unordered_set>
#include <algorithm>

using namespace std;

class Solution {
public:
    bool wordBreak(string s, vector<string>& dictionary) {
        unordered_set<string> wordSet(dictionary.begin(), dictionary.end());
        int strLength = s.length();
        vector<bool> canSegment(strLength + 1, false);
        canSegment[0] = true;  // Base case: empty string can be segmented

        int maxWordLength = 0;
        if (!dictionary.empty()) {
            maxWordLength = max_element(dictionary.begin(), dictionary.end(),
                                        [](const string& a, const string& b) { return a.length() < b.length(); })
                                        ->length();
        }

        for (int end = 1; end <= strLength; ++end) {
            for (int start = max(0, end - maxWordLength); start < end; ++start) {
                if (canSegment[start] && wordSet.count(s.substr(start, end - start))) {
                    canSegment[end] = true;
                    break;
                }
            }
        }
        return canSegment[strLength];
    }
};

 

Time Complexity:

  • Preprocessing Dictionary:

    Building the unordered_set from the dictionary takes \( O(n) \), where \( n \) is the number of words in the dictionary.

  • Finding Maximum Word Length:

    Finding the longest word in the dictionary takes \( O(n) \).

  • Dynamic Programming:

    For each position \( end \) in the string (up to \( m \)), we check up to \( L \) previous positions, leading to a worst-case time complexity of \( O(mL) \), where \( m \) is the length of the input string and \( L \) is the length of the longest word in the dictionary.

  • Substring Lookup:

    Checking if a substring exists in the set takes \( O(1) \) on average but \( O(L) \) in the worst case.

  • Total Time Complexity:

    The overall time complexity is \( O(mL + n) \).

Space Complexity:

  • Dictionary Storage:

    Storing all words in the unordered_set takes \( O(nL) \) space in the worst case.

  • DP Array:

    The canSegment array requires \( O(m) \) space.

  • Total Space Complexity:

    The overall space complexity is \( O(m + nL) \).

from typing import List

class Solution:
    def wordBreak(self, s: str, dictionary: List[str]) -> bool:
        wordSet = set(dictionary)
        strLength = len(s)
        canSegment = [False] * (strLength + 1)
        canSegment[0] = True  

        maxWordLength = max((len(word) for word in dictionary), default=0)

        for end in range(1, strLength + 1):
            for start in range(max(0, end - maxWordLength), end):
                if canSegment[start] and s[start:end] in wordSet:
                    canSegment[end] = True
                    break
        return canSegment[strLength]

 

Time Complexity:

  • Preprocessing Dictionary:

    Building the set from the dictionary takes \( O(n) \), where \( n \) is the number of words in the dictionary.

  • Finding Maximum Word Length:

    Finding the longest word in the dictionary takes \( O(n) \).

  • Dynamic Programming:

    For each position \( end \) in the string (up to \( m \)), we check up to \( L \) previous positions, leading to a worst-case time complexity of \( O(mL) \), where \( m \) is the length of the input string and \( L \) is the length of the longest word in the dictionary.

  • Substring Lookup:

    Checking if a substring exists in the set takes \( O(1) \) on average but \( O(L) \) in the worst case.

  • Total Time Complexity:

    The overall time complexity is \( O(mL + n) \).

Space Complexity:

  • Dictionary Storage:

    Storing all words in the set takes \( O(nL) \) space in the worst case.

  • DP Array:

    The canSegment array requires \( O(m) \) space.

  • Total Space Complexity:

    The overall space complexity is \( O(m + nL) \).

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top