Given a string s and y a dictionary of n words dictionary, check if s
can be segmented into a sequence of valid words from the dictionary, separated by spaces.
Examples:
Input: s = "ilike", dictionary[] = ["i", "like", "gfg"]
Output: true
Explanation: The string can be segmented as "i like".
Input: s = "ilikegfg", dictionary[] = ["i", "like", "man", "india", "gfg"]
Output: true
Explanation: The string can be segmented as "i like gfg".
Input: "ilikemangoes", dictionary = ["i", "like", "gfg"]
Output: false
Explanation: The string cannot be segmented.
[Naive Approach] Using Recursion - O(2^n) Time and O(n) Space
The idea is to consider each prefix and search for it in dictionary. If the prefix is present in dictionary, we recur for rest of the string (or suffix). If the recursive call for suffix returns true, we return true, otherwise we try next prefix. If we have tried all prefixes and none of them resulted in a solution, we return false.
C++
// C++ program to implement word break.
#include <bits/stdc++.h>
using namespace std;
// Function to check if the given string can be broken
// down into words from the word list
bool wordBreakRec(int i, string &s, vector<string> &dictionary)
{
// If end of string is reached,
// return true.
if (i == s.length())
return true;
int n = s.length();
string prefix = "";
// Try every prefix
for (int j = i; j < n; j++)
{
prefix += s[j];
// if the prefix s[i..j] is a dictionary word
// and rest of the string can also be broken into
// valid words, return true
if (find(dictionary.begin(), dictionary.end(), prefix) != dictionary.end() &&
wordBreakRec(j + 1, s, dictionary))
{
return true;
}
}
return false;
}
bool wordBreak(string &s, vector<string> &dictionary)
{
return wordBreakRec(0, s, dictionary);
}
int main()
{
string s = "ilike";
vector<string> dictionary = {"i", "like", "gfg"};
cout << (wordBreak(s, dictionary) ? "true" : "false") << endl;
return 0;
}
Java
import java.util.*;
class GfG {
static boolean wordBreakRec(int i, String s,
String[] dictionary)
{
if (i == s.length())
return true;
String prefix = "";
for (int j = i; j < s.length(); j++) {
prefix += s.charAt(j);
// Check if the prefix exists in the dictionary
if (Arrays.asList(dictionary).contains(prefix)
&& wordBreakRec(j + 1, s, dictionary)) {
return true;
}
}
return false;
}
static boolean wordBreak(String s, String[] dictionary)
{
return wordBreakRec(0, s, dictionary);
}
public static void main(String[] args)
{
String s = "ilike";
String[] dictionary = { "i", "like", "gfg" };
System.out.println(
wordBreak(s, dictionary) ? "true" : "false");
}
}
Python
def wordBreakRec(i, s, dictionary):
# If end of string is reached,
# return true.
if i == len(s):
return 1
n = len(s)
prefix = ""
# Try every prefix
for j in range(i, n):
prefix += s[j]
# if the prefix s[i..j] is a dictionary word
# and rest of the string can also be broken into
# valid words, return true
if prefix in dictionary and wordBreakRec(j + 1, s, dictionary) == 1:
return 1
return 0
def wordBreak(s, dictionary):
return wordBreakRec(0, s, dictionary)
if __name__ == "__main__":
s = "ilike"
dictionary = {"i", "like", "gfg"}
print("true" if wordBreak(s, dictionary) else "false")
C#
using System;
class Program
{
static bool WordBreakRec(int index, string s, string[] dictionary)
{
// If end of the string is reached, return true.
if (index == s.Length)
return true;
string prefix = "";
// Try every prefix from the current index
for (int j = index; j < s.Length; j++)
{
prefix += s[j];
// Check if the current prefix exists in the dictionary
if (Array.Exists(dictionary, word => word == prefix))
{
// If prefix is valid, recursively check for the remaining substring
if (WordBreakRec(j + 1, s, dictionary))
return true;
}
}
return false;
}
static bool WordBreak(string s, string[] dictionary)
{
return WordBreakRec(0, s, dictionary);
}
static void Main()
{
string[] dictionary = {"i", "like", "gfg"};
string s = "ilike";
Console.WriteLine(WordBreak(s, dictionary) ? "true" : "false");
}
}
JavaScript
// JavaScript program to implement word break.
// Function to check if the given string can be broken
// down into words from the word list.
// Returns 1 if string can be segmented
function wordBreakRec(i, s, dictionary)
{
// If end of string is reached,
// return true.
if (i === s.length)
return 1;
let n = s.length;
let prefix = "";
// Try every prefix
for (let j = i; j < n; j++) {
prefix += s[j];
// if the prefix s[i..j] is a dictionary word
// and rest of the string can also be broken into
// valid words, return true
if (dictionary.find((pre) => pre == prefix)
!== undefined
&& wordBreakRec(j + 1, s, dictionary) === 1) {
return 1;
}
}
return 0;
}
function wordBreak(s, dictionary)
{
return wordBreakRec(0, s, dictionary);
}
let s = "ilike";
let dictionary = [ "i", "like", "gfg" ];
console.log(wordBreak(s, dictionary) ? "true" : "false");
[Expected Approach - 1] Using Top-Down DP - O(n^2) Time and O(n+m) Space
The idea is to use dynamic programming in the recursive solution to avoid recomputing same subproblems. To further improve the time complexity, store the words of the dictionary in a set to improve the time complexity of looking for a word in dictionary from O(m) to O(1).
If we notice carefully, we can observe that the above recursive solution holds the following two properties of Dynamic Programming:
1. Optimal Substructure:
To check if the string can be segmented starting from index i, i.e., wordBreakRec(i), depends on the solutions of the subproblems wordBreakRec(j) where j lies between i and n. Return true if s[i:j] is present in dictionary and wordBreakRec(j) returns true.
2. Overlapping Subproblems:
While applying a recursive approach in this problem, we notice that certain subproblems are computed multiple times. For example, for wordBreakRec(0), wordBreakRec(1) and wordBreakRec(2) is called. wordBreakRec(1) will again call wordBreakRec(2).
- There is only one parameter: i that changes in the recursive solution. So we create a 1D array of size n for memoization.
- We initialize this array as -1 to indicate nothing is computed initially.
- Now we modify our recursive solution to first check if the value is -1, then only make recursive calls. This way, we avoid re-computations of the same subproblems.

C++
#include <bits/stdc++.h>
using namespace std;
bool wordBreakRec(int ind, string &s, vector<string> &dictionary, vector<int> &dp)
{
if (ind >= s.size())
{
return true;
}
if (dp[ind] != -1)
return dp[ind];
bool possible = false;
for (int i = 0; i < dictionary.size(); i++)
{
string temp = dictionary[i];
if (temp.size() > s.size() - ind)
continue;
bool ok = true;
int k = ind;
for (int j = 0; j < temp.size(); j++)
{
if (temp[j] != s[k])
{
ok = false;
break;
}
else
k++;
}
if (ok)
{
possible |= wordBreakRec(ind + temp.size(), s, dictionary, dp);
}
}
return dp[ind] = possible;
}
bool wordBreak(string s, vector<string> &dictionary)
{
int n = s.size();
vector<int> dp(n + 1, -1);
string temp = "";
return wordBreakRec(0, s, dictionary, dp);
}
int main()
{
string s = "ilike";
vector<string> dictionary = {"i", "like", "gfg"};
cout << (wordBreak(s, dictionary) ? "true" : "false") << endl;
return 0;
}
Java
import java.util.*;
class GfG {
static boolean wordBreakRec(int ind, String s, String[] dict, int[] dp) {
if (ind >= s.length()) {
return true;
}
if (dp[ind] != -1) {
return dp[ind] == 1;
}
boolean possible = false;
for (String temp : dict) {
if (temp.length() > s.length() - ind) {
continue;
}
boolean ok = true;
int k = ind;
for (int j = 0; j < temp.length(); j++) {
if (temp.charAt(j) != s.charAt(k)) {
ok = false;
break;
}
k++;
}
if (ok) {
possible |= wordBreakRec(ind + temp.length(), s, dict, dp);
}
}
dp[ind] = possible ? 1 : 0;
return possible;
}
public static boolean wordBreak(String s, String[] dict) {
int n = s.length();
int[] dp = new int[n + 1];
Arrays.fill(dp, -1);
return wordBreakRec(0, s, dict, dp);
}
public static void main(String[] args) {
String s = "ilike";
String[] dict = {"i", "like", "gfg"};
System.out.println(wordBreak(s, dict) ? "true" : "false");
}
}
Python
def wordBreakRec(ind, s, dict, dp):
if ind >= len(s):
return True
if dp[ind] != -1:
return dp[ind] == 1
possible = False
for temp in dict:
if len(temp) > len(s) - ind:
continue
if s[ind:ind+len(temp)] == temp:
possible |= wordBreakRec(ind + len(temp), s, dict, dp)
dp[ind] = 1 if possible else 0
return possible
def word_break(s, dict):
n = len(s)
dp = [-1] * (n + 1)
return wordBreakRec(0, s, dict, dp)
s = "ilike"
dict = ["i", "like", "gfg"]
print("true" if word_break(s, dict) else "false")
JavaScript
function wordBreakRec(ind, s, dict, dp) {
if (ind >= s.length) {
return true;
}
if (dp[ind] !== -1) {
return dp[ind] === 1;
}
let possible = false;
for (let temp of dict) {
if (temp.length > s.length - ind) {
continue;
}
if (s.substring(ind, ind + temp.length) === temp) {
possible ||= wordBreakRec(ind + temp.length, s, dict, dp);
}
}
dp[ind] = possible ? 1 : 0;
return possible;
}
function wordBreak(s, dict) {
let n = s.length;
let dp = new Array(n + 1).fill(-1);
return wordBreakRec(0, s, dict, dp);
}
let s = "ilike";
let dict = ["i", "like", "gfg"];
console.log(wordBreak(s, dict) ? "true" : "false");
[Expected Approach - 2] Using Bottom Up DP - O(n*m*k) time and O(n) space
The idea is to use bottom-up dynamic programming to determine if a string can be segmented into dictionary words. Create a boolean array d[] where each position dp[i] represents whether the substring from 0 to that position can be broken into dictionary words.
Step by step approach:
- Start from the beginning of the string and mark it as valid (base case). i.e., dp[0] = true
- For each position, check if any dictionary word ends at that position and leads to an already valid position.
- If such a word exists, mark the current position as valid, i.e., dp[i] = true
- At the end return the last entry of dp[]
C++
// C++ program to implement word break.
#include <bits/stdc++.h>
using namespace std;
bool wordBreak(string &s, vector<string> &dictionary)
{
int n = s.size();
vector<bool> dp(n + 1, 0);
dp[0] = 1;
// Traverse through the given string
for (int i = 1; i <= n; i++)
{
// Traverse through the dictionary words
for (string &w : dictionary)
{
// Check if current word is present
// the prefix before the word is also
// breakable
int start = i - w.size();
if (start >= 0 && dp[start] && s.substr(start, w.size()) == w)
{
dp[i] = 1;
break;
}
}
}
return dp[n];
}
int main()
{
string s = "ilike";
vector<string> dictionary = {"i", "like", "gfg"};
cout << (wordBreak(s, dictionary) ? "true" : "false") << endl;
return 0;
}
Java
import java.util.*;
class GfG {
static boolean wordBreak(String s, String[] dictionary)
{
int n = s.length();
boolean[] dp = new boolean[n + 1];
dp[0] = true;
// Traverse through the given string
for (int i = 1; i <= n; i++) {
// Traverse through the dictionary words
for (String w : dictionary) {
// Check if the current word is present and
// the prefix before the word is also
// breakable
int start = i - w.length();
if (start >= 0 && dp[start]
&& s.substring(start,
start + w.length())
.equals(w)) {
dp[i] = true;
break;
}
}
}
return dp[n]; // Returning true or false
}
public static void main(String[] args)
{
String s = "ilike";
String[] dictionary
= { "i", "like", "gfg" }; // Using String array
System.out.println(
wordBreak(s, dictionary) ? "true" : "false");
}
}
Python
# Python program to implement word break
def wordBreak(s, dictionary):
n = len(s)
dp = [False] * (n + 1)
dp[0] = True
# Traverse through the given string
for i in range(1, n + 1):
# Traverse through the dictionary words
for w in dictionary:
# Check if current word is present
# the prefix before the word is also
# breakable
start = i - len(w)
if start >= 0 and dp[start] and s[start:start + len(w)] == w:
dp[i] = True
break
return 1 if dp[n] else 0
if __name__ == '__main__':
s = "ilike"
dictionary = ["i", "like", "gfg"]
print("true" if wordBreak(s, dictionary) else "false")
C#
using System;
using System.Collections.Generic;
class GfG {
static bool wordBreak(string s, string[] dictionary)
{
int n = s.Length;
bool[] dp = new bool[n + 1];
dp[0] = true;
// Traverse through the given string
for (int i = 1; i <= n; i++) {
// Traverse through the dictionary words
foreach(string w in dictionary)
{
// Check if current word is present and the
// prefix before the word is also breakable
int start = i - w.Length;
if (start >= 0 && dp[start]
&& s.Substring(start, w.Length) == w) {
dp[i] = true;
break;
}
}
}
return dp[n]; // Return true if word break is
// possible, else false
}
public static void Main()
{
string s = "ilike";
string[] dictionary
= { "i", "like", "gfg" }; // Using string array
Console.WriteLine(
wordBreak(s, dictionary) ? "true" : "false");
}
}
JavaScript
// JavaScript program to implement word break
function wordBreak(s, dictionary)
{
const n = s.length;
const dp = new Array(n + 1).fill(false);
dp[0] = true;
// Traverse through the given string
for (let i = 1; i <= n; i++) {
// Traverse through the dictionary words
for (const w of dictionary) {
// Check if current word is present
// the prefix before the word is also
// breakable
const start = i - w.length;
if (start >= 0 && dp[start]
&& s.substring(start, start + w.length)
=== w) {
dp[i] = true;
break;
}
}
}
return (dp[n]) ? 1 : 0;
}
const s = "ilike";
const dictionary = [ "i", "like", "gfg" ];
console.log(wordBreak(s, dictionary) ? "true" : "false");
Time Complexity: O(n * m * k), where n is the length of string and m is the number of dictionary words and k is the length of maximum sized string in dictionary.
Space Complexity: O(n)
Related Articles:
Word Break Problem | (Trie solution)
Word Break Problem using Backtracking
Similar Reads
Basics & Prerequisites
Data Structures
Array Data StructureIn this article, we introduce array, implementation in different popular languages, its basic operations and commonly seen problems / interview questions. An array stores items (in case of C/C++ and Java Primitive Arrays) or their references (in case of Python, JS, Java Non-Primitive) at contiguous
3 min read
String in Data StructureA string is a sequence of characters. The following facts make string an interesting data structure.Small set of elements. Unlike normal array, strings typically have smaller set of items. For example, lowercase English alphabet has only 26 characters. ASCII has only 256 characters.Strings are immut
2 min read
Hashing in Data StructureHashing is a technique used in data structures that efficiently stores and retrieves data in a way that allows for quick access. Hashing involves mapping data to a specific index in a hash table (an array of items) using a hash function. It enables fast retrieval of information based on its key. The
2 min read
Linked List Data StructureA linked list is a fundamental data structure in computer science. It mainly allows efficient insertion and deletion operations compared to arrays. Like arrays, it is also used to implement other data structures like stack, queue and deque. Hereâs the comparison of Linked List vs Arrays Linked List:
2 min read
Stack Data StructureA Stack is a linear data structure that follows a particular order in which the operations are performed. The order may be LIFO(Last In First Out) or FILO(First In Last Out). LIFO implies that the element that is inserted last, comes out first and FILO implies that the element that is inserted first
2 min read
Queue Data StructureA Queue Data Structure is a fundamental concept in computer science used for storing and managing data in a specific order. It follows the principle of "First in, First out" (FIFO), where the first element added to the queue is the first one to be removed. It is used as a buffer in computer systems
2 min read
Tree Data StructureTree Data Structure is a non-linear data structure in which a collection of elements known as nodes are connected to each other via edges such that there exists exactly one path between any two nodes. Types of TreeBinary Tree : Every node has at most two childrenTernary Tree : Every node has at most
4 min read
Graph Data StructureGraph Data Structure is a collection of nodes connected by edges. It's used to represent relationships between different entities. If you are looking for topic-wise list of problems on different topics like DFS, BFS, Topological Sort, Shortest Path, etc., please refer to Graph Algorithms. Basics of
3 min read
Trie Data StructureThe Trie data structure is a tree-like structure used for storing a dynamic set of strings. It allows for efficient retrieval and storage of keys, making it highly effective in handling large datasets. Trie supports operations such as insertion, search, deletion of keys, and prefix searches. In this
15+ min read
Algorithms
Searching AlgorithmsSearching algorithms are essential tools in computer science used to locate specific items within a collection of data. In this tutorial, we are mainly going to focus upon searching in an array. When we search an item in an array, there are two most common algorithms used based on the type of input
2 min read
Sorting AlgorithmsA Sorting Algorithm is used to rearrange a given array or list of elements in an order. For example, a given array [10, 20, 5, 2] becomes [2, 5, 10, 20] after sorting in increasing order and becomes [20, 10, 5, 2] after sorting in decreasing order. There exist different sorting algorithms for differ
3 min read
Introduction to RecursionThe process in which a function calls itself directly or indirectly is called recursion and the corresponding function is called a recursive function. A recursive algorithm takes one step toward solution and then recursively call itself to further move. The algorithm stops once we reach the solution
14 min read
Greedy AlgorithmsGreedy algorithms are a class of algorithms that make locally optimal choices at each step with the hope of finding a global optimum solution. At every step of the algorithm, we make a choice that looks the best at the moment. To make the choice, we sometimes sort the array so that we can always get
3 min read
Graph AlgorithmsGraph is a non-linear data structure like tree data structure. The limitation of tree is, it can only represent hierarchical data. For situations where nodes or vertices are randomly connected with each other other, we use Graph. Example situations where we use graph data structure are, a social net
3 min read
Dynamic Programming or DPDynamic Programming is an algorithmic technique with the following properties.It is mainly an optimization over plain recursion. Wherever we see a recursive solution that has repeated calls for the same inputs, we can optimize it using Dynamic Programming. The idea is to simply store the results of
3 min read
Bitwise AlgorithmsBitwise algorithms in Data Structures and Algorithms (DSA) involve manipulating individual bits of binary representations of numbers to perform operations efficiently. These algorithms utilize bitwise operators like AND, OR, XOR, NOT, Left Shift, and Right Shift.BasicsIntroduction to Bitwise Algorit
4 min read
Advanced
Segment TreeSegment Tree is a data structure that allows efficient querying and updating of intervals or segments of an array. It is particularly useful for problems involving range queries, such as finding the sum, minimum, maximum, or any other operation over a specific range of elements in an array. The tree
3 min read
Pattern SearchingPattern searching algorithms are essential tools in computer science and data processing. These algorithms are designed to efficiently find a particular pattern within a larger set of data. Patten SearchingImportant Pattern Searching Algorithms:Naive String Matching : A Simple Algorithm that works i
2 min read
GeometryGeometry is a branch of mathematics that studies the properties, measurements, and relationships of points, lines, angles, surfaces, and solids. From basic lines and angles to complex structures, it helps us understand the world around us.Geometry for Students and BeginnersThis section covers key br
2 min read
Interview Preparation
Practice Problem