Open In App

Word Break - Find All Ways to Break

Last Updated : 12 Jul, 2025
Comments
Improve
Suggest changes
17 Likes
Like
Report

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

Examples: 

Input: s = "likegfg" , dict[] = ["lik", "like", "egfg", "gfg"]
Output: 
"lik egfg" 
"like gfg"
Explanation: The string "likegfg" is segmented into valid dictionary words in all possible ways: "lik egfg" and "like gfg".

Input: s = "geeksforgeeks" , dict[] = ["for", "geeks"]
Output: 
"geeks for geeks" 
Explanation: The string "geeksforgeeks" can be broken into valid words from the dictionary in one ways.

A similar problem is discussed in the Word Break article, where the task is to check that is there any solution such that the sequence can be broken into the dictionary words.

[Naive Approach] Using Recursion - O((2^n) * k) Time and O(n) Space

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.

Recurrence Relation:

  • wordBreak(s, start) = wordBreak(s, start + len(word)), where word is a substring in the dictionary.

Base Cases:

If the starting index equals the length of the string:
wordBreak(s, start) = true, this signifies that a valid sentence has been constructed for the given input string.

For implementation of the above recursive approach, please refer to Word Break Problem using Backtracking.

[Expected Approach 1] Using Top-Down DP O((n^2)*m) Time and O(n*m) Space

1. Optimal Substructure: The solution to the word break problem can be derived from the solutions of smaller subproblems. Specifically, for any given starting index start, the problem reduces to determining if the substring s[start..end] forms a valid word and combining this with valid sentence breaks for the remaining substring s[end..n].

We can express the recursive relation as follows:

  • For every substring s[start..end] where end > start, check: If the word exists in the dictionary st.count(s.substr(start, end - start)).
  • For each valid result of wordBreakHelper(s, st, memo, end):
    • If it is empty, add only the word.
    • Otherwise, concatenate the word with the sub-sentence using a space.

2. Overlapping Subproblems: When solving the word break problem using recursion, the same subproblems are solved multiple times. For example, if we compute wordBreakHelper(s, st, memo, start) for a certain start, it will recompute results for the same start index in different branches of recursion. To avoid recomputation, we store the results of wordBreakHelper(s, st, memo, start) in a memo map where the key is the index start, and the value is a list of valid sentence breaks starting from that index.

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

// Helper function to perform backtracking with memoization
vector<string> wordBreakHelper(string &s, unordered_set<string> &st, unordered_map<int, vector<string>> &memo,
                               int start)
{

    // If the result for this index is already
    // computed, return it
    if (memo.count(start))
    {
        return memo[start];
    }

    vector<string> result;

    // If start reaches the end of the string,
    // add an empty string to signify a valid sentence
    if (start == s.length())
    {
        result.push_back("");
        return result;
    }

    // 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 set
        if (st.count(word))
        {

            // Recurse for the remaining string
            vector<string> subSentences = wordBreakHelper(s, st, memo, end);

            // Append the current word to each valid sub-sentence
            for (string &sub : subSentences)
            {
                if (sub.empty())
                {
                    result.push_back(word);
                }
                else
                {
                    result.push_back(word + " " + sub);
                }
            }
        }
    }

    // Memoize the result for the current index
    memo[start] = result;
    return result;
}

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

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

    unordered_map<int, vector<string>> memo;

    return wordBreakHelper(s, st, memo, 0);
}

int main()
{

    string s = "likegfg";
    vector<string> dict = {"lik", "like", "egfg", "gfg" };

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

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

    return 0;
}
Java
import java.util.*;

class GfG {
    // Helper function to perform backtracking with
    // memoization
    static String[] wordBreakHelper(
        String s, HashSet<String> st,
        Map<Integer, String[]> memo, int start)
    {

        // If the result for this index is already computed,
        // return it
        if (memo.containsKey(start)) {
            return memo.get(start);
        }

        ArrayList<String> resultList = new ArrayList<>();

        // If start reaches the end of the string,
        // add an empty string to signify a valid sentence
        if (start == s.length()) {
            return new String[] { "" };
        }

        // 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 set
            if (st.contains(word)) {
                // Recurse for the remaining string
                String[] subSentences
                    = wordBreakHelper(s, st, memo, end);

                // Append the current word to each valid
                // sub-sentence
                for (String sub : subSentences) {
                    if (sub.isEmpty()) {
                        resultList.add(word);
                    }
                    else {
                        resultList.add(word + " " + sub);
                    }
                }
            }
        }

        // Convert ArrayList to Array and Memoize the result
        // for the current index
        String[] resultArray
            = resultList.toArray(new String[0]);
        memo.put(start, resultArray);
        return resultArray;
    }

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

        // Convert words array to a HashSet
        HashSet<String> st
            = new HashSet<>(Arrays.asList(dict));

        Map<Integer, String[]> memo = new HashMap<>();

        return wordBreakHelper(s, st, memo, 0);
    }

    public static void main(String[] args)
    {

        String s = "likegfg";
        String[] dict = {"lik", "like", "egfg", "gfg"  };

        String[] result = wordBreak(dict, s);

        for (String sentence : result) {
            System.out.println(sentence);
        }
    }
}
Python
# Python implementation to find valid
# word break using Recursion and Memoization

def wordBreakHelper(s, st, memo, start):

    # If the result for this index is already
    # computed, return it
    if start in memo:
        return memo[start]

    result = []

    # If start reaches the end of the string,
    # add an empty string to signify a valid sentence
    if start == len(s):
        result.append("")
        return result

    # 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 set
        if word in st:

            # Recurse for the remaining string
            subSentences = wordBreakHelper(s, st, memo, end)

            # Append the current word to each valid sub-sentence
            for sub in subSentences:
                if sub:
                    result.append(word + " " + sub)
                else:
                    result.append(word)

    # Memoize the result for the current index
    memo[start] = result
    return result


def wordBreak(dict, s):

    # Convert list to a set
    st = set(dict)

    memo = {}
    return wordBreakHelper(s, st, memo, 0)


if __name__ == '__main__':

    s = "likegfg"
    dict = ["lik", "like", "egfg", "gfg" ]

    result = wordBreak(dict, s)

    for sentence in result:
        print(sentence)
C#
using System;
using System.Collections.Generic;

class GfG {

    // Helper function to perform backtracking
    // with memoization
    static string[] wordBreakHelper(
        string s, HashSet<string> st,
        Dictionary<int, string[]> memo, int start)
    {

        // If the result for this index is already
        // computed, return it
        if (memo.ContainsKey(start)) {
            return memo[start];
        }

        List<string> result = new List<string>();

        // If start reaches the end of the string,
        // add an empty string to signify a valid sentence
        if (start == s.Length) {
            return new string[] { "" };
        }

        // 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 set
            if (st.Contains(word)) {
                string[] subSentences
                    = wordBreakHelper(s, st, memo, end);

                // Append the current word to each valid
                // sub-sentence
                foreach(string sub in subSentences)
                {
                    if (sub.Length > 0) {
                        result.Add(word + " " + sub);
                    }
                    else {
                        result.Add(word);
                    }
                }
            }
        }

        // Memoize the result for the current index
        string[] resultArray = result.ToArray();
        memo[start] = resultArray;
        return resultArray;
    }

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

        // Convert words array to a HashSet
        HashSet<string> st = new HashSet<string>(dict);

        // Dictionary for memoization
        Dictionary<int, string[]> memo
            = new Dictionary<int, string[]>();

        return wordBreakHelper(s, st, memo, 0);
    }

    static void Main()
    {

        string s = "likegfg";
        string[] dict = { "lik", "like", "egfg", "gfg"  };

        string[] result = wordBreak(dict, s);

        foreach(string sentence in result)
        {
            Console.WriteLine(sentence);
        }
    }
}
JavaScript
function wordBreakHelper(s, st, memo, start)
{

    // If the result for this index is already
    // computed, return it
    if (memo.has(start)) {
        return memo.get(start);
    }

    let result = [];

    // If start reaches the end of the string,
    // add an empty string to signify a valid sentence
    if (start === s.length) {
        result.push("");
        return result;
    }

    // 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 (st.has(word)) {
            let subSentences
                = wordBreakHelper(s, st, memo, end);

            // Append the current word to each
            // valid sub-sentence
            for (let sub of subSentences) {
                if (sub.length > 0) {
                    result.push(word + " " + sub);
                }
                else {
                    result.push(word);
                }
            }
        }
    }

    // Memoize the result for the current index
    memo.set(start, result);
    return result;
}

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

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

    // Map for memoization
    let memo = new Map();

    return wordBreakHelper(s, st, memo, 0);
}

let s = "likegfg";
let dict = [ "lik", "like", "egfg", "gfg" ];

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

Output
lik egfg
like gfg

[Expected Approach 2] Using Bottom-Up DP - O((n^2)*m) Time and O(n*m) Space

The approach is similar, but instead of breaking down the problem recursively, we iteratively build up the solution in a bottom-up manner.

We create a DP array dp where dp[i] stores all valid sentences starting from the index i of the string s.

Dynamic Programming Relation

  • For each index i in the string s (processed from the end to the beginning):
  • We iterate over all possible substrings s[i : j] where j > i and j <= n (the length of the string).
  • If s[i : j] exists in the dictionary (st), we append the word s[i : j] to all valid sentences stored in dp[j].
  • Specifically:

dp[i] = Union over j = i + 1 to n: (s[i : j] + " " + sub (sub ∈ dp[j]), s[i : j] ∈ st)

If dp[j] contains an empty string (base case for the end of the string), the word s[i : j] alone forms a valid sentence at dp[i].

Base Case: dp[n] = [""], This signifies that an empty string at the end of s contributes to valid sentences.


C++
// C++ program to find valid word breaks
// using tabulation
#include <bits/stdc++.h>
using namespace std;

// Function to find all valid sentences
vector<string> wordBreak(vector<string> &dict, string &s)
{

    // Convert dictionary to a set for fast lookups
    unordered_set<string> st(dict.begin(), dict.end());

    int n = s.length();

    // dp[i] stores all valid sentences
    // starting from index i
    vector<vector<string>> dp(n + 1);

    // Base case: an empty string at the end
    dp[n] = {""};

    for (int i = n - 1; i >= 0; --i)
    {

        // Check substrings starting from the
        // current index
        for (int j = i + 1; j <= n; ++j)
        {
            string word = s.substr(i, j - i);

            if (st.count(word))
            {

                // Append valid sub-sentences to the
                // current word
                for (string &sub : dp[j])
                {
                    if (sub.empty())
                    {
                        dp[i].push_back(word);
                    }
                    else
                    {
                        dp[i].push_back(word + " " + sub);
                    }
                }
            }
        }
    }

    return dp[0];
}

int main()
{

    string s = "likegfg";
    vector<string> dict = {"lik", "like", "egfg", "gfg" };

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

    for (string s : res)
    {
        cout << s << endl;
    }

    return 0;
}
Java
// Java program to find valid word breaks using tabulation
import java.util.*;

class GfG {

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

        HashSet<String> st
            = new HashSet<>(Arrays.asList(dict));
        int n = s.length();

        // dp[i] stores all valid sentences starting from
        // index i
        List<List<String> > dp = new ArrayList<>();
        for (int i = 0; i <= n; i++) {
            dp.add(new ArrayList<>());
        }

        // Base case: an empty string at the end
        dp.get(n).add("");

        for (int i = n - 1; i >= 0; --i) {

            // Check substrings starting from the current
            // index
            for (int j = i + 1; j <= n; ++j) {
                String word = s.substring(i, j);

                if (st.contains(word)) {

                    // Append valid sub-sentences to the
                    // current word
                    for (String sub : dp.get(j)) {
                        if (sub.isEmpty()) {
                            dp.get(i).add(word);
                        }
                        else {
                            dp.get(i).add(word + " " + sub);
                        }
                    }
                }
            }
        }

        // Convert result list to array before returning
        return dp.get(0).toArray(new String[0]);
    }

    public static void main(String[] args)
    {

        String s = "likegfg";
        String[] dict = {"lik", "like", "egfg", "gfg" };

        String[] result = wordBreak(dict, s);

        for (String sentence : result) {
            System.out.println(sentence);
        }
    }
}
Python
# Python program to find valid word breaks
# using tabulation

def wordBreak(dict, s):

    st = set(dict)
    n = len(s)

    # dp[i] stores all valid sentences
    # starting from index i
    dp = [[] for _ in range(n + 1)]

    # Base case: an empty string at the end
    dp[n].append("")

    for i in range(n - 1, -1, -1):

        # Check substrings starting from the
        # current index
        for j in range(i + 1, n + 1):
            word = s[i:j]

            # Check if the word exists in the
            # dictionary
            if word in st:

                # Append valid sub-sentences to
                # the current word
                for sub in dp[j]:
                    if sub:
                        dp[i].append(word + " " + sub)
                    else:
                        dp[i].append(word)

    return dp[0]


if __name__ == '__main__':

    s = "likegfg"
    dict = ["lik", "like", "egfg", "gfg" ]

    result = wordBreak(dict, s)

    for sentence in result:
        print(sentence)
C#
// C# program to find valid word breaks using tabulation
using System;
using System.Collections.Generic;

class GfG {

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

        HashSet<string> st = new HashSet<string>(dict);
        int n = s.Length;

        // dp[i] stores all valid sentences starting from
        // index i
        List<string>[] dp = new List<string>[ n + 1 ];
        for (int i = 0; i <= n; i++) {
            dp[i] = new List<string>();
        }

        // Base case: an empty string at the end
        dp[n].Add("");

        for (int i = n - 1; i >= 0; i--) {

            // Check substrings starting from the current
            // index
            for (int j = i + 1; j <= n; j++) {
                string word = s.Substring(i, j - i);

                if (st.Contains(word)) {

                    // Append valid sub-sentences to the
                    // current word
                    foreach(var sub in dp[j])
                    {
                        if (sub.Length > 0) {
                            dp[i].Add(word + " " + sub);
                        }
                        else {
                            dp[i].Add(word);
                        }
                    }
                }
            }
        }

        // Convert result list to array before returning
        return dp[0].ToArray();
    }

    static void Main()
    {

        string s = "likegfg";
        string[] dict = {"lik", "like", "egfg", "gfg" };

        string[] result = wordBreak(dict, s);

        foreach(string sentence in result)
        {
            Console.WriteLine(sentence);
        }
    }
}
JavaScript
// JavaScript program to find valid word
// breaks using tabulation

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

    // Convert dictionary array to a Set
    let st = new Set(dict);
    let n = s.length;

    // dp[i] stores all valid sentences
    // starting from index i
    let dp = Array.from({length : n + 1}, () => []);

    // Base case: an empty string at the end
    dp[n].push("");

    for (let i = n - 1; i >= 0; i--) {

        // Check substrings starting from the
        // current index
        for (let j = i + 1; j <= n; j++) {
            let word = s.substring(i, j);

            if (st.has(word)) {

                // Append valid sub-sentences to
                // the current word
                for (let sub of dp[j]) {
                    if (sub.length > 0) {
                        dp[i].push(word + " " + sub);
                    }
                    else {
                        dp[i].push(word);
                    }
                }
            }
        }
    }

    return dp[0];
}

let s = "likegfg";
let dict = ["lik", "like", "egfg", "gfg" ];

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

Output
lik egfg
like gfg

Article Tags :

Explore