Open In App
Related Articles

Minimum Word Break

Improve Article
Improve
Save Article
Save
Like Article
Like

Given a string s, break s such that every substring of the partition can be found in the dictionary. Return the minimum break needed. 

Examples: 

Given a dictionary ["Cat", "Mat", "Ca", 
"tM", "at", "C", "Dog", "og", "Do"]
Input : Pattern "CatMat"
Output : 1
Explanation: we can break the sentences
in three ways, as follows:
CatMat = [ Cat Mat ] break 1
CatMat = [ Ca tM at ] break 2
CatMat = [ C at Mat ] break 2 so the
output is: 1
Input : Dogcat
Output : 1

Asked in: Facebook 

Solution of this problem is based on the WordBreak Trie solution and level ordered graph. We start traversing given pattern and start finding a character of pattern in a trie. If we reach a node(leaf) of a trie from where we can traverse a new word of a trie(dictionary), we increment level by one and call search function for rest of the pattern character in a trie. In the end, we return minimum Break. 

  MinBreak(Trie, key, level, start = 0 )
.... If start == key.length()
...update min_break
for i = start to keylength
....If we found a leaf node in trie
MinBreak( Trie, key, level+1, i )

Below is the implementation of above idea 

C++




// C++ program to find minimum breaks needed
// to break a string in dictionary words.
#include <bits/stdc++.h>
using namespace std;
 
const int ALPHABET_SIZE = 26;
 
// trie node
struct TrieNode {
    struct TrieNode* children[ALPHABET_SIZE];
 
    // isEndOfWord is true if the node
    // represents end of a word
    bool isEndOfWord;
};
 
// Returns new trie node (initialized to NULLs)
struct TrieNode* getNode(void)
{
    struct TrieNode* pNode = new TrieNode;
 
    pNode->isEndOfWord = false;
 
    for (int i = 0; i < ALPHABET_SIZE; i++)
        pNode->children[i] = NULL;
 
    return pNode;
}
 
// If not present, inserts the key into the trie
// If the key is the prefix of trie node, just
// marks leaf node
void insert(struct TrieNode* root, string key)
{
    struct TrieNode* pCrawl = root;
 
    for (int i = 0; i < key.length(); i++) {
        int index = key[i] - 'a';
        if (!pCrawl->children[index])
            pCrawl->children[index] = getNode();
 
        pCrawl = pCrawl->children[index];
    }
 
    // mark last node as leaf
    pCrawl->isEndOfWord = true;
}
 
// function break the string into minimum cut
// such the every substring after breaking
// in the dictionary.
void minWordBreak(struct TrieNode* root,
          string key, int start, int* min_Break,
                                 int level = 0)
{
    struct TrieNode* pCrawl = root;
 
    // base case, update minimum Break
    if (start == key.length()) {       
        *min_Break = min(*min_Break, level - 1);
        return;
    }
 
    // traverse given key(pattern)
    int minBreak = 0;  
    for (int i = start; i < key.length(); i++) {
        int index = key[i] - 'a';
        if (!pCrawl->children[index])
            return;
 
        // if we find a condition where we can
        // move to the next word in a trie
        // dictionary
        if (pCrawl->children[index]->isEndOfWord)
            minWordBreak(root, key, i + 1,
                           min_Break, level + 1);
 
        pCrawl = pCrawl->children[index];
    }
}
 
// Driver program to test above functions
int main()
{
    string dictionary[] = { "Cat", "Mat",
   "Ca", "Ma", "at", "C", "Dog", "og", "Do" };
    int n = sizeof(dictionary) / sizeof(dictionary[0]);
    struct TrieNode* root = getNode();
 
    // Construct trie
    for (int i = 0; i < n; i++)
        insert(root, dictionary[i]);
    int min_Break = INT_MAX;
 
    minWordBreak(root, "CatMatat", 0, &min_Break, 0);
    cout << min_Break << endl;
    return 0;
}


Java




// Java program to find minimum breaks needed
// to break a string in dictionary words.
public class Trie {
 
TrieNode root = new TrieNode();
int minWordBreak = Integer.MAX_VALUE;
 
    // Trie node
    class TrieNode {
        boolean endOfTree;
        TrieNode children[] = new TrieNode[26];
        TrieNode(){
            endOfTree = false;
            for(int i=0;i<26;i++){
                children[i]=null;
            }
        }
    }
 
    // If not present, inserts a key into the trie
    // If the key is the prefix of trie node, just
    // marks leaf node
    void insert(String key){
        int length = key.length();
 
        int index;
 
        TrieNode pcrawl = root;
 
        for(int i = 0; i < length; i++)
        {
            index = key.charAt(i)- 'a';
 
            if(pcrawl.children[index] == null)
                pcrawl.children[index] = new TrieNode();
 
            pcrawl = pcrawl.children[index];
        }
         
        // mark last node as leaf
        pcrawl.endOfTree = true;
 
    }
 
    // function break the string into minimum cut
    // such the every substring after breaking
    // in the dictionary.
    void minWordBreak(String key)
    {
        minWordBreak = Integer.MAX_VALUE;
         
        minWordBreakUtil(root, key, 0, Integer.MAX_VALUE, 0);
    }
     
    void minWordBreakUtil(TrieNode node, String key,
                int start, int min_Break, int level)
    {
        TrieNode pCrawl = node;
 
        // base case, update minimum Break
        if (start == key.length()) {
            min_Break = Math.min(min_Break, level - 1);
            if(min_Break<minWordBreak){
                minWordBreak = min_Break;
            }
            return;
        }
 
        // traverse given key(pattern)
        for (int i = start; i < key.length(); i++) {
            int index = key.charAt(i) - 'a';
            if (pCrawl.children[index]==null)
                return;
 
            // if we find a condition were we can
            // move to the next word in a trie
            // dictionary
            if (pCrawl.children[index].endOfTree) {
                minWordBreakUtil(root, key, i + 1,
                        min_Break, level + 1);
 
            }
            pCrawl = pCrawl.children[index];
        }
    }
 
    // Driver code
    public static void main(String[] args)
    {
        String keys[] = {"cat", "mat", "ca", "ma",
                    "at", "c", "dog", "og", "do" };
 
        Trie trie = new Trie();
 
        // Construct trie
         
        int i;
        for (i = 0; i < keys.length ; i++)
            trie.insert(keys[i]);
         
        trie.minWordBreak("catmatat");
 
        System.out.println(trie.minWordBreak);
    }
}
 
// This code is contributed by Pavan Koli.


Python3




# Python program to find minimum breaks needed
# to break a string in dictionary words.
 
import sys
 
 
class TrieNode:
 
    def __init__(self):
     
        self.endOfTree = False
        self.children = [None for i in range(26)]
         
 
 
root = TrieNode()
minWordBreak = sys.maxsize
 
# If not present, inserts a key into the trie
    # If the key is the prefix of trie node, just
    # marks leaf node
def insert(key):
 
    global root,minWordBreak
 
    length = len(key)
 
    pcrawl = root
 
    for i in range(length):
 
        index = ord(key[i])- ord('a')
 
        if(pcrawl.children[index] == None):
            pcrawl.children[index] = TrieNode()
        pcrawl = pcrawl.children[index]
         
        # mark last node as leaf
        pcrawl.endOfTree = True
 
# function break the string into minimum cut
# such the every substring after breaking
# in the dictionary.
def _minWordBreak(key):
 
    global minWordBreak
 
    minWordBreak = sys.maxsize
         
    minWordBreakUtil(root, key, 0, sys.maxsize, 0)
 
def minWordBreakUtil(node,key,start,min_Break,level):
 
    global minWordBreak,root
 
    pCrawl = node
 
    # base case, update minimum Break
    if (start == len(key)):
            min_Break = min(min_Break, level - 1)
            if(min_Break<minWordBreak):
                minWordBreak = min_Break
             
            return
         
 
    # traverse given key(pattern)
    for i in range(start,len(key)):
        index = ord(key[i]) - ord('a')
        if (pCrawl.children[index]==None):
            return
 
        # if we find a condition were we can
        # move to the next word in a trie
        # dictionary
        if (pCrawl.children[index].endOfTree):
            minWordBreakUtil(root, key, i + 1,min_Break, level + 1)
 
        pCrawl = pCrawl.children[index]
         
 
 
# Driver code
keys=["cat", "mat", "ca", "ma", "at", "c", "dog", "og", "do" ]
 
for i in range(len(keys)):
    insert(keys[i])
 
_minWordBreak("catmatat")
 
print(minWordBreak)
 
# This code is contributed by shinjanpatra


C#




// C# program to find minimum breaks needed
// to break a string in dictionary words.
using System;
 
class Trie
{
 
    TrieNode root = new TrieNode();
    int minWordBreak = int.MaxValue ;
 
    // Trie node
    public class TrieNode
    {
        public bool endOfTree;
        public TrieNode []children = new TrieNode[26];
        public TrieNode()
        {
            endOfTree = false;
            for(int i = 0; i < 26; i++)
            {
                children[i] = null;
            }
        }
    }
 
    // If not present, inserts a key
    // into the trie If the key is the
    // prefix of trie node, just marks leaf node
    void insert(String key)
    {
        int length = key.Length;
 
        int index;
 
        TrieNode pcrawl = root;
 
        for(int i = 0; i < length; i++)
        {
            index = key[i]- 'a';
 
            if(pcrawl.children[index] == null)
                pcrawl.children[index] = new TrieNode();
 
            pcrawl = pcrawl.children[index];
        }
         
        // mark last node as leaf
        pcrawl.endOfTree = true;
 
    }
 
    // function break the string into minimum cut
    // such the every substring after breaking
    // in the dictionary.
    void minWordBreaks(String key)
    {
        minWordBreak = int.MaxValue;
        minWordBreakUtil(root, key, 0, int.MaxValue, 0);
    }
     
    void minWordBreakUtil(TrieNode node, String key,
                int start, int min_Break, int level)
    {
        TrieNode pCrawl = node;
 
        // base case, update minimum Break
        if (start == key.Length)
        {
            min_Break = Math.Min(min_Break, level - 1);
            if(min_Break < minWordBreak)
            {
                minWordBreak = min_Break;
            }
            return;
        }
 
        // traverse given key(pattern)
        for (int i = start; i < key.Length; i++)
        {
            int index = key[i] - 'a';
            if (pCrawl.children[index]==null)
                return;
 
            // if we find a condition were we can
            // move to the next word in a trie
            // dictionary
            if (pCrawl.children[index].endOfTree)
            {
                minWordBreakUtil(root, key, i + 1,
                        min_Break, level + 1);
            }
            pCrawl = pCrawl.children[index];
        }
    }
 
    // Driver code
    public static void Main(String[] args)
    {
        String []keys = {"cat", "mat", "ca", "ma",
                    "at", "c", "dog", "og", "do" };
 
        Trie trie = new Trie();
 
        // Construct trie
        int i;
        for (i = 0; i < keys.Length ; i++)
            trie.insert(keys[i]);
         
        trie.minWordBreaks("catmatat");
        Console.WriteLine(trie.minWordBreak);
    }
}
 
// This code is contributed by 29AjayKumar


Javascript




<script>
 
// JavaScript program to find minimum breaks needed
// to break a string in dictionary words.
 
class TrieNode
{
    constructor()
    {
        this.endOfTree=false;
        this.children=new Array(26);
        for(let i=0;i<26;i++)
            this.children[i]=null;
    }
}
 
let root = new TrieNode();
let minWordBreak = Number.MAX_VALUE;
 
// If not present, inserts a key into the trie
    // If the key is the prefix of trie node, just
    // marks leaf node
function insert(key)
{
    let length = key.length;
   
        let index;
   
        let pcrawl = root;
   
        for(let i = 0; i < length; i++)
        {
            index = key[i].charAt(0)- 'a'.charAt(0);
   
            if(pcrawl.children[index] == null)
                pcrawl.children[index] = new TrieNode();
   
            pcrawl = pcrawl.children[index];
        }
           
        // mark last node as leaf
        pcrawl.endOfTree = true;
}
 
// function break the string into minimum cut
    // such the every substring after breaking
    // in the dictionary.
function _minWordBreak(key)
{
    minWordBreak = Number.MAX_VALUE;
           
    minWordBreakUtil(root, key, 0, Number.MAX_VALUE, 0);
}
 
function minWordBreakUtil(node,key,start,min_Break,level)
{
    let pCrawl = node;
   
        // base case, update minimum Break
        if (start == key.length) {
            min_Break = Math.min(min_Break, level - 1);
            if(min_Break<minWordBreak){
                minWordBreak = min_Break;
            }
            return;
        }
   
        // traverse given key(pattern)
        for (let i = start; i < key.length; i++) {
            let index = key[i].charAt(0) - 'a'.charAt(0);
            if (pCrawl.children[index]==null)
                return;
   
            // if we find a condition were we can
            // move to the next word in a trie
            // dictionary
            if (pCrawl.children[index].endOfTree) {
                minWordBreakUtil(root, key, i + 1,
                        min_Break, level + 1);
   
            }
            pCrawl = pCrawl.children[index];
        }
}
 
// Driver code
let keys=["cat", "mat", "ca", "ma",
                    "at", "c", "dog", "og", "do" ];
 
let i;
for (i = 0; i < keys.length ; i++)
    insert(keys[i]);
 
_minWordBreak("catmatat");
 
document.write(minWordBreak);
 
 
// This code is contributed by rag2127
 
</script>


Output

2







Time Complexity: O(n*n*L) where n is the length of the input string and L is the maximum length of word in the dictionary.
Auxiliary Space: O(ALPHABET_SIZE^L+n*L)

Approach 2: Using Dynamic Programming

  • We maintain an array dp where dp[i] represents the minimum number of breaks needed to break the substring s[0…i-1] into dictionary words. 
  • We initialize dp[0] = 0 since the empty string can be broken into zero words. 
  • For each position i in the string, we iterate over all dictionary words and check if the substring ending at position i matches the current dictionary word. 
  • If it does, we update dp[i] to be the minimum of dp[i] and dp[i – len] + 1, where len is the length of the current dictionary word. 
  • Finally, we return dp[n] – 1, where n is the length of the input string, since the number of breaks needed is one less than the number of words.

C++




#include <bits/stdc++.h>
using namespace std;
 
const int INF = 1e9;
 
int minWordBreak(string s, vector<string>& dict) {
    int n = s.length();
    vector<int> dp(n + 1, INF);
    dp[0] = 0;
 
    for (int i = 1; i <= n; i++) {
        for (string word : dict) {
            int len = word.length();
            if (i >= len && s.substr(i - len, len) == word) {
                dp[i] = min(dp[i], dp[i - len] + 1);
            }
        }
    }
 
    return dp[n] - 1;
}
 
int main() {
    vector<string> dict = {"Cat", "Mat", "Ca", "Ma", "at", "C", "Dog", "og", "Do"};
    string s = "CatMatat";
    cout << minWordBreak(s, dict) << endl;
    return 0;
}


Java




import java.util.*;
 
public class WordBreak {
    static final int INF = (int)1e9;
 
    public static int minWordBreak(String s,
                                   List<String> dict)
    {
        int n = s.length();
        int[] dp = new int[n + 1];
        Arrays.fill(dp, INF);
        dp[0] = 0;
 
        for (int i = 1; i <= n; i++) {
            for (String word : dict) {
                int len = word.length();
                if (i >= len
                    && s.substring(i - len, i)
                           .equals(word)) {
                    dp[i]
                        = Math.min(dp[i], dp[i - len] + 1);
                }
            }
        }
 
        return dp[n] - 1;
    }
 
    public static void main(String[] args)
    {
        List<String> dict
            = Arrays.asList("Cat", "Mat", "Ca", "Ma", "at",
                            "C", "Dog", "og", "Do");
        String s = "CatMatat";
        System.out.println(minWordBreak(s, dict));
    }
}


Python3




def min_word_break(s, dict):
    n = len(s)
    dp = [float('inf')] * (n + 1# Initialize a list to store minimum word breaks needed
    dp[0] = 0  # No breaks needed for an empty string
 
    for i in range(1, n + 1):
        for word in dict:
            length = len(word)
            if i >= length and s[i - length:i] == word:
                # Check if the substring from i-length to i matches a word in the dictionary
                dp[i] = min(dp[i], dp[i - length] + 1)
                # Update the minimum word breaks needed at position i
 
    return dp[n] - 1  # Return the minimum word breaks needed for the entire string
 
def main():
    dict = ["Cat", "Mat", "Ca", "Ma", "at", "C", "Dog", "og", "Do"]
    s = "CatMatat"
    min_breaks = min_word_break(s, dict)
    print(f"The minimum word breaks needed: {min_breaks}")
 
if __name__ == "__main__":
    main()
# This code is contributed by shivamgupta0987654321


C#




using System;
using System.Collections.Generic;
 
public class GFG
{
    const int INF = 1000000000;
    public static int MinWordBreak(string s, List<string> dict)
    {
        int n = s.Length;
        int[] dp = new int[n + 1];
        for (int i = 0; i <= n; i++)
            dp[i] = INF;
        dp[0] = 0;
        for (int i = 1; i <= n; i++)
        {
            foreach (string word in dict)
            {
                int len = word.Length;
                if (i >= len && s.Substring(i - len, len) == word)
                {
                    dp[i] = Math.Min(dp[i], dp[i - len] + 1);
                }
            }
        }
        return dp[n] - 1;
    }
    public static void Main(string[] args)
    {
        List<string> dict = new List<string> { "Cat", "Mat", "Ca", "Ma", "at", "C", "Dog", "og", "Do" };
        string s = "CatMatat";
        int result = MinWordBreak(s, dict);
        Console.WriteLine(result);
    }
}


Javascript




// Define a constant for infinity, which will be used as an initial value in the DP array
const INF = 1e9;
 
// Function to find the minimum word break count
function minWordBreak(s, dict) {
    const n = s.length; // Length of the input string
    const dp = new Array(n + 1).fill(INF); // Initialize a DP array with initially infinite values
    dp[0] = 0; // The base case: No breaks needed for an empty string
 
    // Iterate over the characters in the input string
    for (let i = 1; i <= n; i++) {
        // Iterate over the words in the dictionary
        for (const word of dict) {
            const len = word.length; // Length of the current dictionary word
 
            // Check if the current substring (ending at position i) matches the dictionary word
            if (i >= len && s.substring(i - len, i) === word) {
                // If it matches, update the DP array with the minimum break count
                dp[i] = Math.min(dp[i], dp[i - len] + 1);
            }
        }
    }
 
    return dp[n] - 1; // Subtract 1 to get the minimum break count
}
 
// Driver code
const dict = ["Cat", "Mat", "Ca", "Ma", "at", "C", "Dog", "og", "Do"];
const s = "CatMatat";
console.log("Minimum Word Break Count:", minWordBreak(s, dict));


Output

2








Note that this code has a time complexity of O(n*m), where n is the length of the input string and m is the size of the dictionary. This is because we iterate over all positions in the string and for each position, we iterate over all words in the dictionary.

If you like GeeksforGeeks and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.


Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!

Last Updated : 04 Oct, 2023
Like Article
Save Article
Similar Reads
Related Tutorials