Word Break

Last Updated : 3 Oct, 2026

Given a string s and a list dictionary[] of words. Find whether the string s can be formed by concatenating one or more words from the dictionary[].

Note: From dictionary[], any word can be taken any number of times and in any order.

Examples:

Input: s = "ilike", dictionary[] = ["i", "like", "gfg"]
Output: true
Explanation: s can be breakdown as "i like".

Input: s = "ilikegfg", dictionary[] = ["i", "like", "man", "india", "gfg"]
Output: true
Explanation: s can be breakdown as "i like gfg".

Input: s = "ilikemangoes", dictionary[] = ["i", "like", "man", "india", "gfg"]
Output: false
Explanation: s cannot be formed using dictionary[] words.

Try It Yourself
redirect icon

[Naive Approach] Trying All Prefixes - O(2^n) Time and O(n) Space

The idea is to try every possible prefix of the string.

  • If a prefix is present in the dictionary, we recursively solve for the remaining string.
  • If the remaining string can be broken, the whole string can be broken.

Base Case: If the string becomes empty, all its characters have been matched, return true.

Working of the Approach:

  • Store all dictionary words in a hash set for O(1) average lookups.
  • If the string is empty, return true, as every character has been matched.
  • For each index i from 1 to n, take the prefix s[0..i).
  • If this prefix is present in the set, recursively check the remaining string s[i..n).
  • If any recursive call returns true, return true immediately.
  • If no prefix leads to a valid break, return false.
C++
#include <iostream>
#include <vector>
#include <string>
#include <unordered_set>
using namespace std;

bool wordBreakRec(string s, unordered_set<string> &st) {

    // base case: the whole string is matched
    if (s.empty())
        return true;

    int n = s.length();

    // try every prefix s[0..i)
    for (int i = 1; i <= n; i++) {
        string prefix = s.substr(0, i);

        // if the prefix is a dictionary word, check the remaining string
        if (st.count(prefix) && wordBreakRec(s.substr(i), st))
            return true;
    }

    // no valid break found
    return false;
}

bool wordBreak(string &s, vector<string> &dictionary) {

    // store all dictionary words in a set for fast lookups
    unordered_set<string> st(dictionary.begin(), dictionary.end());

    return wordBreakRec(s, st);
}

int main() {
    string s = "ilike";
    vector<string> dictionary = {"i", "like", "gfg"};

    cout << (wordBreak(s, dictionary) ? "true" : "false") << endl;
    return 0;
}
Java
import java.util.Arrays;
import java.util.HashSet;

class GFG {

    static boolean wordBreakRec(String s, HashSet<String> st) {

        // base case: the whole string is matched
        if (s.isEmpty())
            return true;

        int n = s.length();

        // try every prefix s[0..i)
        for (int i = 1; i <= n; i++) {
            String prefix = s.substring(0, i);

            // if the prefix is a dictionary word, check the remaining string
            if (st.contains(prefix) && wordBreakRec(s.substring(i), st))
                return true;
        }

        // no valid break found
        return false;
    }

    static boolean wordBreak(String s, String[] dictionary) {

        // store all dictionary words in a set for fast lookups
        HashSet<String> st = new HashSet<>(Arrays.asList(dictionary));

        return wordBreakRec(s, st);
    }

    public static void main(String[] args) {
        String s = "ilike";
        String[] dictionary = {"i", "like", "gfg"};

        System.out.println(wordBreak(s, dictionary));
    }
}
Python
def wordBreakRec(s, st):

    # base case: the whole string is matched
    if len(s) == 0:
        return True

    n = len(s)

    # try every prefix s[0..i)
    for i in range(1, n + 1):
        prefix = s[:i]

        # if the prefix is a dictionary word, check the remaining string
        if prefix in st and wordBreakRec(s[i:], st):
            return True

    # no valid break found
    return False


def wordBreak(s, dictionary):

    # store all dictionary words in a set for fast lookups
    st = set(dictionary)

    return wordBreakRec(s, st)


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 wordBreakRec(string s, HashSet<string> st) {

        // base case: the whole string is matched
        if (s.Length == 0)
            return true;

        int n = s.Length;

        // try every prefix s[0..i)
        for (int i = 1; i <= n; i++) {
            string prefix = s.Substring(0, i);

            // if the prefix is a dictionary word, check the remaining string
            if (st.Contains(prefix) && wordBreakRec(s.Substring(i), st))
                return true;
        }

        // no valid break found
        return false;
    }

    static bool wordBreak(string s, string[] dictionary) {

        // store all dictionary words in a set for fast lookups
        HashSet<string> st = new HashSet<string>(dictionary);

        return wordBreakRec(s, st);
    }

    static void Main() {
        string s = "ilike";
        string[] dictionary = {"i", "like", "gfg"};

        Console.WriteLine(wordBreak(s, dictionary) ? "true" : "false");
    }
}
JavaScript
function wordBreakRec(s, st) {

    // base case: the whole string is matched
    if (s.length === 0)
        return true;

    let n = s.length;

    // try every prefix s[0..i)
    for (let i = 1; i <= n; i++) {
        let prefix = s.substring(0, i);

        // if the prefix is a dictionary word, check the remaining string
        if (st.has(prefix) && wordBreakRec(s.substring(i), st))
            return true;
    }

    // no valid break found
    return false;
}

function wordBreak(s, dictionary) {

    // store all dictionary words in a set for fast lookups
    let st = new Set(dictionary);

    return wordBreakRec(s, st);
}

// Driver Code
let s = "ilike";
let dictionary = ["i", "like", "gfg"];

console.log(wordBreak(s, dictionary) ? "true" : "false");

Output
true

[Better Approach 1] Top-Down DP - O(n * m * L) Time and O(n) Space

The idea is to use memoization on the recursive solution to avoid recomputing the same subproblems.

  • Whether the string can be broken starting from index i depends only on i, so we store this result for every index in a 1D array.
  • If an index is reached again through a different combination of words, we return the stored result directly instead of recomputing it.

Working of the Approach:

  • Create an array dp[] of size n + 1 and initialize it with -1, which means the result is not computed yet.
  • If i is equal to or greater than n, return true, as the whole string is matched.
  • If dp[i] is not -1, return the stored result.
  • Loop through every word of the dictionary and skip it if it is longer than the remaining string.
  • If the word matches the string starting from index i, recursively check the remaining string from index i + word length.
  • If any recursive call returns true, the string can be broken from index i.
  • Store the result in dp[i] and return it.

Let us understand with an example:

Input: s = "ilike", dictionary = ["i", "like", "gfg"]

  • wordBreakRec(0): "i" matches -> check index 1, "like" and "gfg" do not match at index 0
  • wordBreakRec(1): "like" matches -> check index 5
  • wordBreakRec(5): end of the string -> true
  • dp[1] = true and dp[0] = true, so the answer is true.

Why Memoization Helps? We can see overlapping subproblems in the following diagram. With memoization, each one is solved at most once, which brings the time down from exponential to O(n * m * L).

wordBreak

C++
#include <iostream>
#include <vector>
#include <string>
using namespace std;

bool wordBreakRec(int ind, string &s, vector<string> &dictionary, vector<int> &dp) {

    // base case: the whole string is matched
    if (ind >= s.size())
        return true;

    // if the result is already computed, return it
    if (dp[ind] != -1)
        return dp[ind];

    bool possible = false;

    // try every word of the dictionary
    for (int i = 0; i < dictionary.size(); i++) {
        string word = dictionary[i];

        // skip the word if it is longer than the remaining string
        if (word.size() > s.size() - ind)
            continue;

        // check if the word matches the string starting from index ind
        bool ok = true;
        int k = ind;
        for (int j = 0; j < word.size(); j++) {
            if (word[j] != s[k]) {
                ok = false;
                break;
            }
            k++;
        }

        // if it matches, check the remaining string
        if (ok)
            possible |= wordBreakRec(ind + word.size(), s, dictionary, dp);
    }

    // store the result before returning
    return dp[ind] = possible;
}

bool wordBreak(string s, vector<string> &dictionary) {
    int n = s.size();
    vector<int> dp(n + 1, -1);
    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.Arrays;

class GFG {

    static boolean wordBreakRec(int ind, String s, String[] dictionary, int[] dp) {

        // base case: the whole string is matched
        if (ind >= s.length())
            return true;

        // if the result is already computed, return it
        if (dp[ind] != -1)
            return dp[ind] == 1;

        boolean possible = false;

        // try every word of the dictionary
        for (String word : dictionary) {

            // skip the word if it is longer than the remaining string
            if (word.length() > s.length() - ind)
                continue;

            // check if the word matches the string starting from index ind
            boolean ok = s.startsWith(word, ind);

            // if it matches, check the remaining string
            if (ok)
                possible |= wordBreakRec(ind + word.length(), s, dictionary, dp);
        }

        // store the result before returning
        dp[ind] = possible ? 1 : 0;
        return possible;
    }

    static boolean wordBreak(String s, String[] dictionary) {
        int n = s.length();
        int[] dp = new int[n + 1];
        Arrays.fill(dp, -1);
        return wordBreakRec(0, s, dictionary, dp);
    }

    public static void main(String[] args) {
        String s = "ilike";
        String[] dictionary = {"i", "like", "gfg"};

        System.out.println(wordBreak(s, dictionary));
    }
}
Python
def wordBreakRec(ind, s, dictionary, dp):

    # base case: the whole string is matched
    if ind >= len(s):
        return True

    # if the result is already computed, return it
    if dp[ind] != -1:
        return dp[ind] == 1

    possible = False

    # try every word of the dictionary
    for word in dictionary:

        # skip the word if it is longer than the remaining string
        if len(word) > len(s) - ind:
            continue

        # check if the word matches the string starting from index ind
        ok = s.startswith(word, ind)

        # if it matches, check the remaining string
        if ok:
            possible |= wordBreakRec(ind + len(word), s, dictionary, dp)

    # store the result before returning
    dp[ind] = 1 if possible else 0
    return possible


def wordBreak(s, dictionary):
    n = len(s)
    dp = [-1] * (n + 1)
    return wordBreakRec(0, s, dictionary, dp)


if __name__ == "__main__":
    s = "ilike"
    dictionary = ["i", "like", "gfg"]

    print("true" if wordBreak(s, dictionary) else "false")
C#
using System;

class GFG {

    static bool wordBreakRec(int ind, string s, string[] dictionary, int[] dp) {

        // base case: the whole string is matched
        if (ind >= s.Length)
            return true;

        // if the result is already computed, return it
        if (dp[ind] != -1)
            return dp[ind] == 1;

        bool possible = false;

        // try every word of the dictionary
        foreach (string word in dictionary) {

            // skip the empty word
            if (word.Length == 0)
                continue;

            // skip the word if it is longer than the remaining string
            if (word.Length > s.Length - ind)
                continue;

            // check if the word matches the string starting from index ind
            bool ok = string.CompareOrdinal(s, ind, word, 0, word.Length) == 0;

            // if it matches, check the remaining string
            if (ok)
                possible |= wordBreakRec(ind + word.Length, s, dictionary, dp);
        }

        // store the result before returning
        dp[ind] = possible ? 1 : 0;
        return possible;
    }

    static bool wordBreak(string s, string[] dictionary) {
        int n = s.Length;
        int[] dp = new int[n + 1];
        Array.Fill(dp, -1);
        return wordBreakRec(0, s, dictionary, dp);
    }

    static void Main() {
        string s = "ilike";
        string[] dictionary = {"i", "like", "gfg"};
        Console.WriteLine(wordBreak(s, dictionary) ? "true" : "false");
    }
}
JavaScript
function wordBreakRec(ind, s, dictionary, dp) {

    // base case: the whole string is matched
    if (ind >= s.length)
        return true;

    // if the result is already computed, return it
    if (dp[ind] !== -1)
        return dp[ind] === 1;

    let possible = false;

    // try every word of the dictionary
    for (let word of dictionary) {

        // skip the word if it is longer than the remaining string
        if (word.length > s.length - ind)
            continue;

        // check if the word matches the string starting from index ind
        let ok = s.startsWith(word, ind);

        // if it matches, check the remaining string
        if (ok)
            possible |= wordBreakRec(ind + word.length, s, dictionary, dp);
    }

    // store the result before returning
    dp[ind] = possible ? 1 : 0;
    return possible === true || possible === 1;
}

function wordBreak(s, dictionary) {
    let n = s.length;
    let dp = new Array(n + 1).fill(-1);
    return wordBreakRec(0, s, dictionary, dp);
}

// Driver Code
let s = "ilike";
let dictionary = ["i", "like", "gfg"];

console.log(wordBreak(s, dictionary) ? "true" : "false");

Output
true

[Better Approach 2] Bottom-Up DP - O(n * m * L) Time and O(n) Space

The idea is to use bottom-up dynamic programming to check if the string can be broken into dictionary words. Create a boolean array dp[] of size n + 1, where dp[i] is true if the prefix s[0..i) can be broken into dictionary words.

Working of the Approach:

  1. Mark dp[0] = true, as an empty prefix is always valid (base case).
  2. For each position i from 1 to n, check every dictionary word that ends at position i.
  3. If such a word starts at a position j where dp[j] is true, then dp[i] = true.
  4. At the end, return dp[n].


C++
#include <iostream>
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]; 
    }

    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
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]; 
                      
    }

    public static void Main()
    {
        string s = "ilike";
        string[] dictionary = { "i", "like", "gfg" }; 

        Console.WriteLine(wordBreak(s, dictionary) ? "true" : "false");
    }
}
JavaScript
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");

Output
true

[Expected Approach] Trie and DP - O(n * L + m * L) Time and O(n + m * L) Space

In the earlier DP approaches, we compare every word (or every substring) at each position, which costs O(L) per check.

The idea is to store all dictionary words in a Trie, so that we can match many words at the same position in a single walk.

We do the following after building Trie,

  • We start from index i and move forward character by character, and the walk stops as soon as no word shares the current prefix.
  • Whenever we reach the end of a word, the position right after it becomes a valid break point.

Working of the Approach:

  • Insert all dictionary words into a Trie, and mark the last node of each word as the end of a word.
  • Create a boolean array dp[] of size n + 1, where dp[i] is true if the prefix s[0..i) can be broken into dictionary words.
  • Mark dp[0] = true, as an empty prefix is always valid (base case).
  • For each index i from 0 to n - 1, skip it if dp[i] is false, as no word can start from an unreachable position.
  • If dp[i] is true, start from the root of the Trie and move along the characters s[i], s[i + 1], and so on.
  • If the current character has no child in the Trie, stop, as no dictionary word has this prefix.
  • If the current node marks the end of a word, set dp[j + 1] = true, where j is the index of the current character.
  • At the end, return dp[n].

Let us understand with an example:

Input: s = "ilike", dictionary = ["i", "like", "gfg"]

  • dp[0] = true, start from index 0 -> 'i' is the end of the word "i" -> dp[1] = true, next 'l' has no child -> stop
  • dp[1] = true, start from index 1 -> l, i, k, e follow the word "like" -> 'e' is the end of a word -> dp[5] = true
  • dp[2], dp[3], dp[4] are false, so they are skipped
  • dp[5] = true, so the answer is true.
C++
#include <iostream>
#include <vector>
#include <string>
using namespace std;

// trie node with 26 children, isEnd marks the end of a word
struct TrieNode {
    TrieNode* children[26];
    bool isEnd;

    TrieNode() {
        isEnd = false;
        for (int i = 0; i < 26; i++)
            children[i] = nullptr;
    }
};

// inserts a word into the trie
void insertWord(TrieNode* root, string &word) {
    TrieNode* curr = root;
    for (char c : word) {
        int idx = c - 'a';
        if (curr->children[idx] == nullptr)
            curr->children[idx] = new TrieNode();
        curr = curr->children[idx];
    }
    curr->isEnd = true;
}

bool wordBreak(string &s, vector<string> &dictionary) {
    int n = s.size();

    // insert all dictionary words into the trie
    TrieNode* root = new TrieNode();
    for (string &w : dictionary)
        insertWord(root, w);

    // dp[i] is true if s[0..i) can be broken into dictionary words
    vector<bool> dp(n + 1, false);

    // base case: an empty prefix is always valid
    dp[0] = true;

    // traverse through the given string
    for (int i = 0; i < n; i++) {

        // skip the position if no word can start from it
        if (!dp[i])
            continue;

        // walk down the trie starting from index i
        TrieNode* curr = root;
        for (int j = i; j < n; j++) {
            int idx = s[j] - 'a';

            // stop if no word has this prefix
            if (curr->children[idx] == nullptr)
                break;

            curr = curr->children[idx];

            // if a word ends here, mark the next position as valid
            if (curr->isEnd)
                dp[j + 1] = true;
        }
    }

    // the answer is stored at the last position
    return dp[n];
}

int main() {
    string s = "ilike";
    vector<string> dictionary = {"i", "like", "gfg"};

    cout << (wordBreak(s, dictionary) ? "true" : "false") << endl;
    return 0;
}
Java
// trie node with 26 children, isEnd marks the end of a word
class TrieNode {
    TrieNode[] children = new TrieNode[26];
    boolean isEnd = false;
}

class GFG {

    // inserts a word into the trie
    static void insertWord(TrieNode root, String word) {
        TrieNode curr = root;
        for (char c : word.toCharArray()) {
            int idx = c - 'a';
            if (curr.children[idx] == null)
                curr.children[idx] = new TrieNode();
            curr = curr.children[idx];
        }
        curr.isEnd = true;
    }

    static boolean wordBreak(String s, String[] dictionary) {
        int n = s.length();

        // insert all dictionary words into the trie
        TrieNode root = new TrieNode();
        for (String w : dictionary)
            insertWord(root, w);

        // dp[i] is true if s[0..i) can be broken into dictionary words
        boolean[] dp = new boolean[n + 1];

        // base case: an empty prefix is always valid
        dp[0] = true;

        // traverse through the given string
        for (int i = 0; i < n; i++) {

            // skip the position if no word can start from it
            if (!dp[i])
                continue;

            // walk down the trie starting from index i
            TrieNode curr = root;
            for (int j = i; j < n; j++) {
                int idx = s.charAt(j) - 'a';

                // stop if no word has this prefix
                if (curr.children[idx] == null)
                    break;

                curr = curr.children[idx];

                // if a word ends here, mark the next position as valid
                if (curr.isEnd)
                    dp[j + 1] = true;
            }
        }

        // the answer is stored at the last position
        return dp[n];
    }

    public static void main(String[] args) {
        String s = "ilike";
        String[] dictionary = {"i", "like", "gfg"};

        System.out.println(wordBreak(s, dictionary));
    }
}
Python
# trie node with 26 children, isEnd marks the end of a word
class TrieNode:
    def __init__(self):
        self.children = [None] * 26
        self.isEnd = False


# inserts a word into the trie
def insertWord(root, word):
    curr = root
    for c in word:
        idx = ord(c) - ord('a')
        if curr.children[idx] is None:
            curr.children[idx] = TrieNode()
        curr = curr.children[idx]
    curr.isEnd = True


def wordBreak(s, dictionary):
    n = len(s)

    # insert all dictionary words into the trie
    root = TrieNode()
    for w in dictionary:
        insertWord(root, w)

    # dp[i] is true if s[0..i) can be broken into dictionary words
    dp = [False] * (n + 1)

    # base case: an empty prefix is always valid
    dp[0] = True

    # traverse through the given string
    for i in range(n):

        # skip the position if no word can start from it
        if not dp[i]:
            continue

        # walk down the trie starting from index i
        curr = root
        for j in range(i, n):
            idx = ord(s[j]) - ord('a')

            # stop if no word has this prefix
            if curr.children[idx] is None:
                break

            curr = curr.children[idx]

            # if a word ends here, mark the next position as valid
            if curr.isEnd:
                dp[j + 1] = True

    # the answer is stored at the last position
    return dp[n]


if __name__ == "__main__":
    s = "ilike"
    dictionary = ["i", "like", "gfg"]

    print("true" if wordBreak(s, dictionary) else "false")
C#
using System;

// trie node with 26 children, isEnd marks the end of a word
class TrieNode {
    public TrieNode[] children = new TrieNode[26];
    public bool isEnd = false;
}

class GFG {

    // inserts a word into the trie
    static void insertWord(TrieNode root, string word) {
        TrieNode curr = root;
        foreach (char c in word) {
            int idx = c - 'a';
            if (curr.children[idx] == null)
                curr.children[idx] = new TrieNode();
            curr = curr.children[idx];
        }
        curr.isEnd = true;
    }

    static bool wordBreak(string s, string[] dictionary) {
        int n = s.Length;

        // insert all dictionary words into the trie
        TrieNode root = new TrieNode();
        foreach (string w in dictionary)
            insertWord(root, w);

        // dp[i] is true if s[0..i) can be broken into dictionary words
        bool[] dp = new bool[n + 1];

        // base case: an empty prefix is always valid
        dp[0] = true;

        // traverse through the given string
        for (int i = 0; i < n; i++) {

            // skip the position if no word can start from it
            if (!dp[i])
                continue;

            // walk down the trie starting from index i
            TrieNode curr = root;
            for (int j = i; j < n; j++) {
                int idx = s[j] - 'a';

                // stop if no word has this prefix
                if (curr.children[idx] == null)
                    break;

                curr = curr.children[idx];

                // if a word ends here, mark the next position as valid
                if (curr.isEnd)
                    dp[j + 1] = true;
            }
        }

        // the answer is stored at the last position
        return dp[n];
    }

    static void Main() {
        string s = "ilike";
        string[] dictionary = {"i", "like", "gfg"};

        Console.WriteLine(wordBreak(s, dictionary) ? "true" : "false");
    }
}
JavaScript
// trie node with 26 children, isEnd marks the end of a word
class TrieNode {
    constructor() {
        this.children = new Array(26).fill(null);
        this.isEnd = false;
    }
}

// inserts a word into the trie
function insertWord(root, word) {
    let curr = root;
    for (let c of word) {
        let idx = c.charCodeAt(0) - 'a'.charCodeAt(0);
        if (curr.children[idx] === null)
            curr.children[idx] = new TrieNode();
        curr = curr.children[idx];
    }
    curr.isEnd = true;
}

function wordBreak(s, dictionary) {
    let n = s.length;

    // insert all dictionary words into the trie
    let root = new TrieNode();
    for (let w of dictionary)
        insertWord(root, w);

    // dp[i] is true if s[0..i) can be broken into dictionary words
    let dp = new Array(n + 1).fill(false);

    // base case: an empty prefix is always valid
    dp[0] = true;

    // traverse through the given string
    for (let i = 0; i < n; i++) {

        // skip the position if no word can start from it
        if (!dp[i])
            continue;

        // walk down the trie starting from index i
        let curr = root;
        for (let j = i; j < n; j++) {
            let idx = s.charCodeAt(j) - 'a'.charCodeAt(0);

            // stop if no word has this prefix
            if (curr.children[idx] === null)
                break;

            curr = curr.children[idx];

            // if a word ends here, mark the next position as valid
            if (curr.isEnd)
                dp[j + 1] = true;
        }
    }

    // the answer is stored at the last position
    return dp[n];
}

// Driver Code
let s = "ilike";
let dictionary = ["i", "like", "gfg"];

console.log(wordBreak(s, dictionary) ? "true" : "false");

Output
true
Comment