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.
**Approach:
For the recursive approach, there are two cases at each step (the size of the string **decreases in each step):
- **Include the current substring in the solution, If the substring exists in the dictionary, **recursively check for the rest of the string starting from the next index.
- **Skip the current substring and move to the next possible substring starting from the same index.
**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:
- Convert the dictionary into a hash set for quick search.
- If the **start index reaches the **length of the string (s), it signifies a valid sentence has been constructed. **Add the current sentence (curr) to the result.
- Loop through **every **substring starting at **start and **ending at **all possible positions (end).
- For each substring, check if it **exists in the dictionary (dictSet).
- **If valid:
- **Append the word to the current sentence (curr).
- **Recursively call the function for the remaining part of the string (from end onwards).
- After the recursive call returns, **restore the state of **curr to ensure the next branch of exploration starts with the **correct sentence. C++ `
// 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 = prevdef wordBreak(s, dict):
# Convert dictionary list to a set
dictSet = set(dict)
res = []
curr = ""
wordBreakHelper(s, dictSet, curr, res, 0)
return resif 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.