CSES Solutions Word Combinations (original) (raw)

Last Updated : 23 Jul, 2025

You are given a string **S of length N and a dictionary **arr[] containing K words. In how many ways can you create the string using the words?

**Examples:

**Input: S = "ababc", K = 4, arr[] = {ab, abab, c, cb}
**Output: 2
**Explanation: The possible ways are "ab" + "ab" + "c" and "abab" + "c".

**Input: S = "geeksforgeeks", K = 3, arr[] = {geeks, for, geeks}
**Output: 2
**Explanation: The possible ways are "geeks" + "for" + "geeks" and "geeks" + "for" + "geeks" .

**Approach: To solve the problem, follow the below idea:

The problem can be solved by Dynamic Programming and Tries. We can maintain a dp[] array such that dp[i] stores the number of ways to form the substring S[i...N-1]. We can travverse the string S from right to left and for every index i, **dp[i] is the sum of all dp[j + 1] such that S[i...j] is present in the dictionary. In order to check whether dp[i...j] is present in the dictionary or not, we can insert all the words in a trie and mark the ending of each word with a flag. So, for every index i, we iterate j from i to N-1 and if S[i...j] is present in the dictionary, we add dp[j] to dp[i]. After all the iterations, dp[0] will store the answer.

**Step-by-Step algorithm:

Below is the implementation of the algorithm:

C++ `

#include <bits/stdc++.h> using namespace std;

#define ll long long const int mod = 1e9 + 7;

// Declare the DP array and the Trie data structure vector dp(5005); vector<vector > trie(1e6 + 5, vector(26)); vector isEndOfWord(1e6 + 5); int trieNodeCount = 0;

// Function to insert a word into the Trie void insertWordInTrie(string& word) { int currentNode = 0; for (char& ch : word) { if (!trie[currentNode][ch - 'a']) trie[currentNode][ch - 'a'] = ++trieNodeCount; currentNode = trie[currentNode][ch - 'a']; } isEndOfWord[currentNode] = true; }

// Function to count the number of ways to form the string // from index 'start' int countWays(int start, string& S) { int currentNode = 0, ways = 0; for (int i = start; i < S.size(); i++) { if (!trie[currentNode][S[i] - 'a']) return ways; currentNode = trie[currentNode][S[i] - 'a']; // If a word ends here, add the number of ways from the next index if (isEndOfWord[currentNode]) ways = (ways + dp[i + 1]) % mod; } return ways; }

void solve(string& S, int K, string word[]) { for (int i = 0; i < K; i++) { // Insert each word into the Trie insertWordInTrie(word[i]); } // Base case: One way to form an empty string dp[S.size()] = 1; for (int i = S.size() - 1; i >= 0; i--) { // Fill the DP table from right to left dp[i] = countWays(i, S); } // The answer is the number of ways to form the string from index 0 cout << dp[0]; } // Driver Code int main() { // Input from user string S = "ababc"; int K = 4; string arr[] = { "ab", "abab", "c", "cb" }; solve(S, K, arr); return 0; }

Java

import java.util.Arrays;

public class Main { static final int MOD = (int) 1e9 + 7; static int[] dp = new int[5005]; static int[][] trie = new int[(int) 1e6 + 5][26]; static boolean[] isEndOfWord = new boolean[(int) 1e6 + 5]; static int trieNodeCount = 0;

// Function to insert a word into the Trie
static void insertWordInTrie(String word) {
    int currentNode = 0;
    for (char ch : word.toCharArray()) {
        if (trie[currentNode][ch - 'a'] == 0)
            trie[currentNode][ch - 'a'] = ++trieNodeCount;
        currentNode = trie[currentNode][ch - 'a'];
    }
    isEndOfWord[currentNode] = true;
}

// Function to count the number of ways to form the string
// from index 'start'
static int countWays(int start, String S) {
    int currentNode = 0, ways = 0;
    for (int i = start; i < S.length(); i++) {
        if (trie[currentNode][S.charAt(i) - 'a'] == 0)
            return ways;
        currentNode = trie[currentNode][S.charAt(i) - 'a'];
        // If a word ends here, add the number of ways from the next index
        if (isEndOfWord[currentNode])
            ways = (ways + dp[i + 1]) % MOD;
    }
    return ways;
}

static void solve(String S, int K, String[] words) {
    for (int i = 0; i < K; i++) {
        // Insert each word into the Trie
        insertWordInTrie(words[i]);
    }
    // Base case: One way to form an empty string
    dp[S.length()] = 1;
    for (int i = S.length() - 1; i >= 0; i--) {
        // Fill the DP table from right to left
        dp[i] = countWays(i, S);
    }
    // The answer is the number of ways to form the string from index 0
    System.out.println(dp[0]);
}

// Driver Code
public static void main(String[] args) {
    // Input from user
    String S = "ababc";
    int K = 4;
    String[] arr = { "ab", "abab", "c", "cb" };
    solve(S, K, arr);
}

}

// This code is contributed by rambabuguphka

Python

MOD = 10**9 + 7

Declare the DP array and the Trie data structure

dp = [0] * 5005 trie = [[0] * 26 for _ in range(106 + 5)] isEndOfWord = [False] * (106 + 5) trieNodeCount = 0

Function to insert a word into the Trie

def insertWordInTrie(word): global trieNodeCount currentNode = 0 for ch in word: index = ord(ch) - ord('a') if not trie[currentNode][index]: trieNodeCount += 1 trie[currentNode][index] = trieNodeCount currentNode = trie[currentNode][index] isEndOfWord[currentNode] = True

Function to count the number of ways to form the string

from index 'start'

def countWays(start, S): currentNode = 0 ways = 0 for i in range(start, len(S)): index = ord(S[i]) - ord('a') if not trie[currentNode][index]: return ways currentNode = trie[currentNode][index] # If a word ends here, add the number of ways from the next index if isEndOfWord[currentNode]: ways = (ways + dp[i + 1]) % MOD return ways

def solve(S, K, word): for w in word: # Insert each word into the Trie insertWordInTrie(w) # Base case: One way to form an empty string dp[len(S)] = 1 for i in range(len(S) - 1, -1, -1): # Fill the DP table from right to left dp[i] = countWays(i, S) # The answer is the number of ways to form the string from index 0 print(dp[0])

Driver Code

if name == "main": # Input from user S = "ababc" K = 4 arr = ["ab", "abab", "c", "cb"] solve(S, K, arr)

C#

using System;

public class Gfg { const int MOD = 1000000007; static int[] dp = new int[5005]; static int[,] trie = new int[1000005, 26]; static bool[] isEndOfWord = new bool[1000005]; static int trieNodeCount = 0;

// Function to insert a word into the Trie
static void InsertWordInTrie(string word)
{
    int currentNode = 0;
    foreach (char ch in word)
    {
        if (trie[currentNode, ch - 'a'] == 0)
            trie[currentNode, ch - 'a'] = ++trieNodeCount;
        currentNode = trie[currentNode, ch - 'a'];
    }
    isEndOfWord[currentNode] = true;
}

// Function to count the number of ways to form the string
// from index 'start'
static int CountWays(int start, string S)
{
    int currentNode = 0, ways = 0;
    for (int i = start; i < S.Length; i++)
    {
        if (trie[currentNode, S[i] - 'a'] == 0)
            return ways;
        currentNode = trie[currentNode, S[i] - 'a'];
        // If a word ends here, add the number of ways from the next index
        if (isEndOfWord[currentNode])
            ways = (ways + dp[i + 1]) % MOD;
    }
    return ways;
}

static void Solve(string S, int K, string[] words)
{
    for (int i = 0; i < K; i++)
    {
        // Insert each word into the Trie
        InsertWordInTrie(words[i]);
    }
    // Base case: One way to form an empty string
    dp[S.Length] = 1;
    for (int i = S.Length - 1; i >= 0; i--)
    {
        // Fill the DP table from right to left
        dp[i] = CountWays(i, S);
    }
    // The answer is the number of ways to form the string from index 0
    Console.WriteLine(dp[0]);
}

// Driver Code
public static void Main(string[] args)
{
    // Input from user
    string S = "ababc";
    int K = 4;
    string[] arr = { "ab", "abab", "c", "cb" };
    Solve(S, K, arr);
}

}

JavaScript

const mod = 1e9 + 7;

// Declare the DP array and the Trie data structure let dp = new Array(5005).fill(0); let trie = new Array(1e6 + 5).fill(null).map(() => new Array(26).fill(0)); let isEndOfWord = new Array(1e6 + 5).fill(false); let trieNodeCount = 0;

// Function to insert a word into the Trie function insertWordInTrie(word) { let currentNode = 0; for (let ch of word) { if (!trie[currentNode][ch.charCodeAt(0) - 'a'.charCodeAt(0)]) { trie[currentNode][ch.charCodeAt(0) - 'a'.charCodeAt(0)] = ++trieNodeCount; } currentNode = trie[currentNode][ch.charCodeAt(0) - 'a'.charCodeAt(0)]; } isEndOfWord[currentNode] = true; }

// Function to count the number of ways to form the string // from index 'start' function countWays(start, S) { let currentNode = 0; let ways = 0; for (let i = start; i < S.length; i++) { if (!trie[currentNode][S.charCodeAt(i) - 'a'.charCodeAt(0)]) { return ways; } currentNode = trie[currentNode][S.charCodeAt(i) - 'a'.charCodeAt(0)]; // If a word ends here, add the number of ways from the next index if (isEndOfWord[currentNode]) { ways = (ways + dp[i + 1]) % mod; } } return ways; }

function solve(S, K, word) { for (let i = 0; i < K; i++) { // Insert each word into the Trie insertWordInTrie(word[i]); } // Base case: One way to form an empty string dp[S.length] = 1; for (let i = S.length - 1; i >= 0; i--) { // Fill the DP table from right to left dp[i] = countWays(i, S); } // The answer is the number of ways to form the string from index 0 console.log(dp[0]); }

// Driver Code function main() { // Input from user let S = "ababc"; let K = 4; let arr = ["ab", "abab", "c", "cb"]; solve(S, K, arr); }

main();

// This code is contributed by Ayush Mishra

`

**Time complexity: O(N * N + N * K), where **N is the number of length of **S and **K is the number of words in the dictionary.
**Auxiliary Space: O(N * K)