Given a non-empty sequence S and a dictionary dict[] containing a list of non-empty words, print all possible ways to break the sentence in individual dictionary words.
Examples:
Input: S = “catsanddog”
dict[] = {“cat”, “cats”, “and”, “sand”, “dog”}
Output:
“cats and dog”
“cat sand dog”
Input: S = “pineapplepenapple”
dict[] = {“apple”, “pen”, “applepen”, “pine”, “pineapple”}
Output:
“pine apple pen apple”
“pineapple pen apple”
“pine applepen apple”
A similar problem to this is discussed in this article, where the task is to check that is there any solution such that the sequence can be broken into the dictionary words.
Approach: The idea is to check for every substring starting from any position I , such that it ends at the length of the string which is present in the dictionary then simply recurse for the substring [0, I]. Meanwhile, store the overlapping subproblems for each substring to avoid the computation of the subproblem again. Overlapping subproblems can be shown as follows –
Below is the implementation of the above approach:
// C++ implementation to break // a sequence into the words of // the dictionary #include <bits/stdc++.h> using namespace std;
// Unordered_map used for storing // the sentences the key string // can be broken into unordered_map<string, vector<string> > mp;
// Unordered_set used // to store the dictionary. unordered_set<string> dict; // Utility function used for // printing the obtained result void printResult(vector<string> A)
{ for ( int i = 0; i < A.size(); i++)
cout << A[i] << '\n' ;
} // Utility function for // appending new words // to already existing strings vector<string> combine( vector<string> prev, string word){
// Loop to find the append string
// which can be broken into
for ( int i = 0; i < prev.size(); i++) {
prev[i] += " " + word;
}
return prev;
} // Utility function for word Break vector<string> wordBreakUtil(string s) { // Condition to check if the
// subproblem is already computed
if (mp.find(s) != mp.end())
return mp[s];
vector<string> res;
// If the whole word is a dictionary
// word then directly append into
// the result array for the string
if (dict.find(s) != dict.end())
res.push_back(s);
// Loop to iterate over the substring
for ( int i = 1; i < s.length(); i++) {
string word = s.substr(i);
// If the substring is present into
// the dictionary then recurse for
// other substring of the string
if (dict.find(word) != dict.end()) {
string rem = s.substr(0, i);
vector<string> prev =
combine(wordBreakUtil(rem), word);
res.insert(res.end(),
prev.begin(), prev.end());
}
}
// Store the subproblem
// into the map
mp[s] = res;
return res;
} // Master wordBreak function converts // the string vector to unordered_set vector<string> wordBreak(string s, vector<string>& wordDict)
{ // Clear the previous stored data
mp.clear();
dict.clear();
dict.insert(wordDict.begin(), wordDict.end());
return wordBreakUtil(s);
} // Driver Code int main()
{ vector<string> wordDict1 = {
"cat" , "cats" , "and" , "sand" , "dog" };
printResult(wordBreak( "catsanddog" , wordDict1));
return 0;
} |
import java.util.*;
import java.io.*;
// Java program for the above approach class GFG{
// Unordered_map used for storing
// the sentences the key String
// can be broken into
static TreeMap<String, ArrayList<String>> mp =
new TreeMap<String, ArrayList<String>>();
// Unordered_set used
// to store the dictionary.
static TreeSet<String> dict = new TreeSet<String>();
// Utility function used for
// printing the obtained result
static void printResult(ArrayList<String> A)
{
for ( int i = 0 ; i < A.size() ; i++){
System.out.println(A.get(i));
}
}
// Utility function for
// appending new words
// to already existing strings
static ArrayList<String> combine(ArrayList<String> prev, String word){
// Loop to find the append String
// which can be broken into
for ( int i = 0 ; i < prev.size() ; i++) {
prev.set(i, prev.get(i) + " " + word);
}
return prev;
}
// Utility function for word Break
static ArrayList<String> wordBreakUtil(String s)
{
// Condition to check if the
// subproblem is already computed
if (mp.containsKey(s)){
return mp.get(s);
}
ArrayList<String> res = new ArrayList<String>();
// If the whole word is a dictionary
// word then directly append into
// the result array for the String
if (dict.contains(s))
res.add(s);
// Loop to iterate over the substring
for ( int i = 1 ; i < s.length() ; i++) {
String word = s.substring(i);
// If the substring is present into
// the dictionary then recurse for
// other substring of the String
if (dict.contains(word)) {
String rem = s.substring( 0 , i);
ArrayList<String> prev = combine(wordBreakUtil(rem), word);
for ( int j = 0 ; j < prev.size() ; j++){
res.add(prev.get(j));
}
}
}
// Store the subproblem
// into the map
mp.put(s, res);
return res;
}
// Master wordBreak function converts
// the String vector to unordered_set
static ArrayList<String> wordBreak(String s, ArrayList<String> wordDict)
{
// Clear the previous stored data
mp.clear();
dict.clear();
dict.addAll(wordDict);
return wordBreakUtil(s);
}
// Driver Code
public static void main(String args[])
{
ArrayList<String> wordDict1 = new ArrayList<String>(
List.of( "cat" , "cats" , "and" , "sand" , "dog" )
);
printResult(wordBreak( "catsanddog" , wordDict1));
}
} // This code is contributed by subhamgoyal2014. |
# Python3 implementation to break # a sequence into the words of # the dictionary # Unordered_map used for storing # the sentences the key string # can be broken into mp = dict ()
# Unordered_set used # to store the dictionary. dict_t = set ()
# Utility function used for # printing the obtained result def printResult(A):
for i in range ( len (A)):
print (A[i])
# Utility function for # appending new words # to already existing strings def combine( prev, word):
# Loop to find the append string
# which can be broken into
for i in range ( len (prev)):
prev[i] + = " " + word;
return prev;
# Utility function for word Break def wordBreakUtil(s):
# Condition to check if the
# subproblem is already computed
if (s in mp):
return mp[s];
res = []
# If the whole word is a dictionary
# word then directly append into
# the result array for the string
if (s in dict_t):
res.append(s);
# Loop to iterate over the substring
for i in range ( 1 , len (s)):
word = s[i:];
# If the substring is present into
# the dictionary then recurse for
# other substring of the string
if (word in dict_t):
rem = s[:i]
prev = combine(wordBreakUtil(rem), word);
for i in prev:
res.append(i)
# Store the subproblem
# into the map
#res is an reference so we need to assign an reference to something if its keep on changing
#res values changes after it start going through combine method
#you can check if you had a doubt so here we just clone res
x = []
for i in res:
x.append(i)
mp[s] = x;
return res;
# Master wordBreak function converts # the string vector to unordered_set def wordBreak(s, wordDict):
# Clear the previous stored data
mp.clear();
dict_t.clear();
for i in wordDict:
dict_t.add(i)
return wordBreakUtil(s);
# Driver Code if __name__ = = '__main__' :
wordDict1 = [ "cat" , "cats" , "and" , "sand" , "dog" ]
printResult(wordBreak( "catsanddog" , wordDict1));
# This code is contributed by rutvik_56 |
using System;
using System.Collections.Generic;
class GFG
{ // Dictionary used for storing
// the sentences the key String
// can be broken into
static Dictionary< string , List< string >> mp = new Dictionary< string , List< string >>();
// HashSet used
// to store the dictionary.
static HashSet< string > dict = new HashSet< string >();
// Utility function used for
// printing the obtained result
static void printResult(List< string > A)
{
foreach ( string str in A)
{
Console.WriteLine(str);
}
}
// Utility function for
// appending new words
// to already existing strings
static List< string > combine(List< string > prev, string word)
{
// Loop to find the append String
// which can be broken into
for ( int i = 0; i < prev.Count; i++)
{
prev[i] = prev[i] + " " + word;
}
return prev;
}
// Utility function for word Break
static List< string > wordBreakUtil( string s)
{
// Condition to check if the
// subproblem is already computed
if (mp.ContainsKey(s))
{
return mp[s];
}
List< string > res = new List< string >();
// If the whole word is a dictionary
// word then directly append into
// the result array for the String
if (dict.Contains(s))
res.Add(s);
// Loop to iterate over the substring
for ( int i = 1; i < s.Length; i++)
{
string word = s.Substring(i);
// If the substring is present into
// the dictionary then recurse for
// other substring of the String
if (dict.Contains(word))
{
string rem = s.Substring(0, i);
List< string > prev = combine(wordBreakUtil(rem), word);
for ( int j = 0; j < prev.Count; j++)
{
res.Add(prev[j]);
}
}
}
// Store the subproblem
// into the map
mp[s] = res;
return res;
}
// Master wordBreak function converts
// the String vector to HashSet
static List< string > wordBreak( string s, List< string > wordDict)
{
// Clear the previous stored data
mp.Clear();
dict.Clear();
dict.UnionWith(wordDict);
return wordBreakUtil(s);
}
// Driver Code
static void Main( string [] args)
{
List< string > wordDict1 = new List< string >() { "cat" , "cats" , "and" , "sand" , "dog" };
printResult(wordBreak( "catsanddog" , wordDict1));
}
} // This code is contributed by lokeshpotta20. |
<script> // JavaScript implementation to break // a sequence into the words of // the dictionary // Unordered_map used for storing // the sentences the key string // can be broken into let mp = new Map()
// Unordered_set used // to store the dictionary. let dict_t = new Set()
// Utility function used for // printing the obtained result function printResult(A){
for (let i=0;i<A.length;i++)
document.write(A[i], "</br>" )
} // Utility function for // pushing new words // to already existing strings function combine(prev, word){
// Loop to find the push string
// which can be broken into
for (let i=0;i<prev.length;i++)
prev[i] += " " + word;
return prev;
} // Utility function for word Break function wordBreakUtil(s){
// Condition to check if the
// subproblem is already computed
if (mp.has(s))
return mp.get(s)
let res = []
// If the whole word is a dictionary
// word then directly push into
// the result array for the string
if (dict_t.has(s))
res.push(s);
// Loop to iterate over the substring
for (let i=1;i<s.length;i++){
let word = s.substring(i,)
// If the substring is present into
// the dictionary then recurse for
// other substring of the string
if (dict_t.has(word)){
let rem = s.substring(0,i)
let prev = combine(wordBreakUtil(rem), word);
for (let i of prev)
res.push(i)
}
}
// Store the subproblem
// into the map
// res is an reference so we need to assign an reference to something if its keep on changing
// res values changes after it start going through combine method
// you can check if you had a doubt so here we just clone res
let x=[]
for (let i of res)
x.push(i)
mp.set(s, x)
return res
} // Master wordBreak function converts // the string vector to unordered_set function wordBreak(s, wordDict){
// Clear the previous stored data
mp.clear();
dict_t.clear();
for (let i of wordDict)
dict_t.add(i)
return wordBreakUtil(s);
} // Driver Code let wordDict1 = [ "cat" , "cats" , "and" , "sand" , "dog" ];
printResult(wordBreak( "catsanddog" , wordDict1));
// This code is contributed by shinjanpatra </script> |
cat sand dog cats and dog
Time Complexity: O(2^N), where N is the length of the given string.
Auxiliary Space: O(S + N). where S is the sum of all characters of wordDict1.
// Another approach in C++ #include <bits/stdc++.h> using namespace std;
vector<string> wordBreak( int n, unordered_set<string> Dict,
string s)
{ int l = s.length();
vector<vector<string> > dp(l);
// Here storing word which can be obtain from given
// index
for ( int i = 0; i < l; i++) {
vector<string> arr;
for ( int j = i + 1; j < l + 1; j++) {
if (Dict.find(s.substr(i, j - i)) != Dict.end())
arr.push_back(s.substr(i, j - i));
}
dp[i] = arr;
}
// From bottom up aprroch form the string
vector<vector<string> > sol(l);
for ( int i = l - 1; i >= 0; i--) {
vector<string> ans;
if (dp[i].size()) {
for ( auto word : dp[i]) {
// If word is last word in string directly
// append
if (i + word.length() == l)
ans.push_back(word);
// Combine with each word present already
// and store
else if (sol[i + word.length()].size()) {
for ( auto w : sol[i + word.length()])
ans.push_back(word + " " + w);
}
}
}
sol[i] = ans;
}
return sol[0];
} void print(vector<string> ans)
{ for ( auto x : ans) {
cout << x << "\n" ;
}
} int main()
{ int n = 5;
unordered_set<string> Dict(
{ "cats" , "cat" , "and" , "sand" , "dog" });
string s = "catsanddog" ;
print(wordBreak(n, Dict, s));
return 0;
} // This code is contributed by Abhijeet Kumar(abhijeet19403) |
// Another approach in Java import java.util.*;
class GFG {
static List<String>
wordBreak( int n, HashSet<String> Dict, String s)
{
int l = s.length();
List<List<String> > dp = new ArrayList<>();
// Here storing word which can be obtain from given
// index
for ( int i = 0 ; i < l; i++) {
List<String> arr = new ArrayList<>();
for ( int j = i + 1 ; j < l + 1 ; j++) {
if (Dict.contains(s.substring(i, j)))
arr.add(s.substring(i, j));
}
dp.add(arr);
}
// From bottom up approach form the string
List<List<String> > sol = new ArrayList<>();
for ( int i = 0 ; i < l; i++) {
sol.add( new ArrayList<>());
}
for ( int i = l - 1 ; i >= 0 ; i--) {
List<String> ans = new ArrayList<>();
if (dp.get(i).size() != 0 ) {
for (String word : dp.get(i)) {
// If word is last word in string
// directly append
if (i + word.length() == l)
ans.add(word);
// Combine with each word present
// already and store
else if (sol.get(i + word.length())
.size()
!= 0 ) {
for (String w :
sol.get(i + word.length()))
ans.add(word + " " + w);
}
}
}
sol.set(i, ans);
}
return sol.get( 0 );
}
static void print(List<String> ans)
{
for (String x : ans) {
System.out.println(x);
}
}
public static void main(String[] args)
{
int n = 5 ;
List<String> words = Arrays.asList(
"cats" , "cat" , "and" , "sand" , "dog" );
HashSet<String> Dict = new HashSet<String>(words);
Dict.addAll(words);
String s = "catsanddog" ;
print(wordBreak(n, Dict, s));
}
} // This code is contributed by karandeep1234. |
# Another approach in Python3 def wordBreak(n, Dict , s):
# code here
l = len (s)
dp = [ 0 ] * l
# Here storing word which can be obtain from given index
for i in range (l):
arr = []
for j in range (i + 1 , l + 1 ):
if ( s[i:j] in Dict ):
arr.append(s[i:j])
dp[i] = arr
# From bottom up aprroch form the string
sol = [ 0 ] * l
for i in range (l - 1 , - 1 , - 1 ):
ans = []
if dp[i]:
for word in dp[i]:
# If word is last word in string directly append
if ( i + len (word) = = l):
ans.append(word)
# Combine with each word present already and store
elif ( sol[i + len (word)] ):
for w in sol[i + len (word)]:
ans.append(word + " " + w)
sol[i] = ans
return sol[ 0 ]
if __name__ = = '__main__' :
n = 5
Dict = { "cats" , "cat" , "and" , "sand" , "dog" }
s = "catsanddog"
print (wordBreak(n, Dict , s))
|
using System;
using System.Collections.Generic;
class GFG
{ public static List< string > wordBreak( int n, HashSet< string > Dict, string s)
{
int l = s.Length;
List<List< string >> dp = new List<List< string >>();
// Here storing word which can be obtain from given index
for ( int i = 0; i < l; i++)
{
List< string > arr = new List< string >();
for ( int j = i + 1; j < l + 1; j++)
{
if (Dict.Contains(s.Substring(i, j - i)))
{
arr.Add(s.Substring(i, j - i));
}
}
dp.Add(arr);
}
// From bottom up approach form the string
List<List< string >> sol = new List<List< string >>();
for ( int i = 0; i < l; i++)
{
sol.Add( new List< string >());
}
for ( int i = l - 1; i >= 0; i--)
{
List< string > ans = new List< string >();
if (dp[i].Count > 0)
{
foreach ( string word in dp[i])
{
// If word is last word in string directly
// append
if (i + word.Length == l)
{
ans.Add(word);
}
// Combine with each word present already
// and store
else if (sol[i + word.Length].Count > 0)
{
foreach ( string w in sol[i + word.Length])
{
ans.Add(word + " " + w);
}
}
}
}
sol[i] = ans;
}
return sol[0];
}
static void Main( string [] args)
{
int n = 5;
HashSet< string > Dict = new HashSet< string >{ "cats" , "cat" , "and" , "sand" , "dog" };
string s = "catsanddog" ;
List< string > result = wordBreak(n, Dict, s);
foreach ( string item in result)
{
Console.WriteLine(item);
}
}
} // this code is contributed by poojaagarwal2. |
// Javascript code for the above approach function wordBreak(n, Dict, s)
{ // code here
let l = s.length;
let dp = new Array(l).fill(0);
// Here storing word which can be obtain from given index
for (let i = 0; i < l; i++) {
let arr = [];
for (let j = i+1; j <= l; j++) {
if (Dict.has(s.slice(i, j))) {
arr.push(s.slice(i, j));
}
}
dp[i] = arr;
}
// From bottom up aprroch form the string
let sol = new Array(l).fill(0);
for (let i = l-1; i >= 0; i--) {
let ans = [];
if (dp[i].length > 0) {
for (let word of dp[i]) {
// If word is last word in string directly append
if (i + word.length === l) {
ans.push(word);
}
// Combine with each word present already and store
else if (sol[i + word.length]) {
for (let w of sol[i + word.length]) {
ans.push(word + " " + w);
}
}
}
}
sol[i] = ans;
}
return sol[0];
} let n = 5;
let Dict = new Set([ "cats" , "cat" , "and" , "sand" , "dog" ]);
let s = "catsanddog" ;
document.write(wordBreak(n, Dict, s)[0]+ "<br>" +wordBreak(n, Dict, s)[1]);
// This code is contributed by ik_9 |
cat sand dog cats and dog
Time complexity: The time complexity of this code is O(n^3 * k), where n is the length of the input string and k is the maximum length of a word in the dictionary. The nested loops for creating the dp array takes O(n^3 * k) time, and the loops for forming the final output takes O(n^2 * k) time.
Space complexity: The space complexity of this code is O(n^2 * k), where n is the length of the input string and k is the maximum length of a word in the dictionary. The dp array takes O(n^2 * k) space, and the final output vector takes O(n^2 * k) space in the worst case.