Word Break Problem using Backtracking (original) (raw)

Last Updated : 25 Nov, 2024

Given a non-empty sequence s and a dictionary **dict[] containing a list of non-empty words, the task is to return all possible ways to break the sentence in **individual dictionary words.
**Note: The same word in the dictionary may be reused **multiple times while breaking.
**Examples:

**Input: s = “catsanddog” , dict = [“cat”, “cats”, “and”, “sand”, “dog”]
**Output:
“cats and dog”
“cat sand dog”
**Explanation: The string is split into above 2 ways, in each way all are valid dictionary words.

**Input: s = “pineapplepenapple” , dict = [“apple”, “pen”, “applepen”, “pine”, “pineapple”]
**Output:
“pine apple pen apple”
“pineapple pen apple”
“pine applepen apple”
**Explanation: The string is split into above 3 ways, in each way all are valid dictionary words.

Try It Yourselfredirect icon

**Approach:

For the recursive approach, there are two cases at each step (the size of the string **decreases in each step):

**wordBreak(s,start) = wordBreak(s, end) , if s[start:end] ∈ dictionary

**Base Case : wordBreak(s, start) = true_, this signifies that a valid sentence has been constructed for the given input string.

Steps to implement the above idea:

// C++ implementation to find valid word // break using Recursion #include <bits/stdc++.h> using namespace std;

// Helper function to perform backtracking void wordBreakHelper(string& s, unordered_set& dictSet, string& curr, vector& res, int start) {

// If start reaches the end of the string,
// save the result
if (start == s.length()) {
    res.push_back(curr);
    return;
}

// Try every possible substring from the current index
for (int end = start + 1; end <= s.length(); ++end) {
    string word = s.substr(start, end - start);

    // Check if the word exists in the dictionary
    if (dictSet.count(word)) {
        string prev = curr;

        // Append the word to the current sentence
        if (!curr.empty()) {
            curr += " ";
        }
        curr += word;

        // Recurse for the remaining string
        wordBreakHelper(s, dictSet, curr, res, end);

        // Backtrack to restore the current sentence
        curr = prev;
    }
}

}

// Main function to generate all possible sentence breaks vector wordBreak(string s, vector& dict) {

// Convert dictionary vector
// to an unordered set
unordered_set<string>
       dictSet(dict.begin(), dict.end());

vector<string> res; 
string curr; 

wordBreakHelper(s, dictSet, curr, res, 0);

return res; 

}

int main() {

string s = "ilikesamsungmobile";
vector<string> dict = {"i", "like", "sam", "sung",
                       "samsung", "mobile", "ice",
                        "and", "cream", "icecream",
                        "man", "go", "mango"};

vector<string> result = wordBreak(s, dict);

for (string sentence : result) {
    cout << sentence << endl;
}

return 0;

}

Java

// Java implementation to find valid // word break using Recursion import java.util.*;

class GfG {

// Helper function to perform backtracking
static void wordBreakHelper(String s, HashSet<String> dictSet, 
                                   String curr, List<String> res, 
                                   int start) {

    // If start reaches the end of the string,
    // save the result
    if (start == s.length()) {
        res.add(curr);
        return;
    }

    // Try every possible substring from the current index
    for (int end = start + 1; end <= s.length(); ++end) {
        String word = s.substring(start, end);

        // Check if the word exists in the dictionary
        if (dictSet.contains(word)) {
            String prev = curr;

            // Append the word to the current sentence
            if (!curr.isEmpty()) {
                curr += " ";
            }
            curr += word;

            // Recurse for the remaining string
            wordBreakHelper(s, dictSet, curr, res, end);

            // Backtrack to restore the current sentence
            curr = prev;
        }
    }
}

// Main function to generate all possible sentence breaks
static List<String> wordBreak(String s, List<String> dict) {

    // Convert dictionary vector to a HashSet
    HashSet<String> dictSet = new HashSet<>(dict);

    List<String> res = new ArrayList<>();
    String curr = "";

    wordBreakHelper(s, dictSet, curr, res, 0);

    return res;
}

public static void main(String[] args) {

    String s = "ilikesamsungmobile";
    List<String> dict = Arrays.asList("i", "like", "sam", "sung",
                       "samsung", "mobile", "ice",
                        "and", "cream", "icecream",
                        "man", "go", "mango");

    List<String> result = wordBreak(s, dict);

    for (String sentence : result) {
        System.out.println(sentence);
    }
}

}

Python

Python implementation to find valid

word break using Recursion

def wordBreakHelper(s, dictSet, curr, res, start):

# If start reaches the end of the string,
# save the result
if start == len(s):
    res.append(curr)
    return

# Try every possible substring from the current index
for end in range(start + 1, len(s) + 1):
    word = s[start:end]

    # Check if the word exists in the dictionary
    if word in dictSet:
        prev = curr

        # Append the word to the current sentence
        if curr:
            curr += " "
        curr += word

        # Recurse for the remaining string
        wordBreakHelper(s, dictSet, curr, res, end)

        # Backtrack to restore the current sentence
        curr = prev

def wordBreak(s, dict):

# Convert dictionary list to a set
dictSet = set(dict)

res = []
curr = ""

wordBreakHelper(s, dictSet, curr, res, 0)

return res

if name=='main':

s = "ilikesamsungmobile"
dict = ["i", "like", "sam", "sung",
                       "samsung", "mobile", "ice",
                        "and", "cream", "icecream",
                        "man", "go", "mango"]

result = wordBreak(s, dict)

for sentence in result:
    print(sentence)

C#

// C# implementation to find valid word // break using Recursion using System; using System.Collections.Generic;

class GfG {

// Helper function to perform backtracking
static void wordBreakHelper(string s, HashSet<string> dictSet,
                      ref string curr, ref List<string> res,
                      int start) {
  
    // If start reaches the end of the string,
    // save the result
    if (start == s.Length) {
        res.Add(curr);
        return;
    }

    // Try every possible substring from the current index
    for (int end = start + 1; end <= s.Length; ++end) {
      
        string word = s.Substring(start, end - start);

        // Check if the word exists in the dictionary
        if (dictSet.Contains(word)) {
            string prev = curr;

            // Append the word to the current sentence
            if (curr.Length > 0) {
                curr += " ";
            }
            curr += word;

            // Recurse for the remaining string
            wordBreakHelper(s, dictSet, ref curr, 
                                         ref res, end);

            // Backtrack to restore the current sentence
            curr = prev;
        }
    }
}

// Main function to generate all possible sentence breaks
static List<string> wordBreak(string s, 
                                  List<string> dict) {
  
    // Convert dictionary list to a HashSet
    HashSet<string> dictSet 
           = new HashSet<string>(dict);

    List<string> res = new List<string>();
    string curr = "";

    wordBreakHelper(s, dictSet, ref curr, ref res, 0);

    return res;
}

static void Main() {
  
    string s = "ilikesamsungmobile";
    List<string> dict
         = new List<string> {"i", "like", "sam", "sung",
                       "samsung", "mobile", "ice",
                        "and", "cream", "icecream",
                        "man", "go", "mango"};

    List<string> result = wordBreak(s, dict);

    foreach (string sentence in result) {
        Console.WriteLine(sentence);
    }
}

}

JavaScript

// JavaScript implementation to find valid // word break using Recursion

// Helper function to perform backtracking function wordBreakHelper(s, dictSet, curr, res, start) {

// If start reaches the end of the string, save the result
if (start === s.length) {
    res.push(curr);
    return;
}

// Try every possible substring from the current index
for (let end = start + 1; end <= s.length; ++end) {
    let word = s.substring(start, end);

    // Check if the word exists in the dictionary
    if (dictSet.has(word)) {
        let prev = curr;

        // Append the word to the current sentence
        if (curr.length > 0) {
            curr += " ";
        }
        curr += word;

        // Recurse for the remaining string
        wordBreakHelper(s, dictSet, curr, res, end);

        // Backtrack to restore the current sentence
        curr = prev;
    }
}

}

// Main function to generate all possible sentence breaks function wordBreak(s, dict) {

// Convert dictionary array to a Set
let dictSet = new Set(dict);

let res = [];
let curr = "";

wordBreakHelper(s, dictSet, curr, res, 0);

return res;

}

let s = "ilikesamsungmobile"; let dict = ["i", "like", "sam", "sung", "samsung", "mobile", "ice", "and", "cream", "icecream", "man", "go", "mango"];

let result = wordBreak(s, dict); result.forEach((sentence) => { console.log(sentence); });

`

Output

i like sam sung mobile i like samsung mobile

**Time Complexity: O((2^n) * k), for a string of length n, there are 2^n possible partitions, and each substring check takes O(k) time (average substring length k), leading to O((2^n) * k).
**Auxiliary Space: O(n), due to the recursion stack can go as deep as O(n) in the worst case.