All LCS in Lexicographical Order

Last Updated : 14 Jun, 2026

Given two strings s1 and s2, return all distinct Longest Common Subsequences (LCS) in lexicographical order.

Examples: 

Input: s1 = "abac", s2 = "aabca"
Output: ["aac", "aba", "abc"]
Explanation: Every subsequence that appears in both "abac" and "aabca" with the maximum possible length 3, are ["aac" ,"aba", "abc"]

Input: s1 = "baaa", s2 = "ca"
Output: ["a"]
Explanation: Every subsequence common to "baaa and "ca" of maximum length 1, is ["a"].

Try It Yourself
redirect icon

[Naive Approach] Generate All Subsequences - O(2ⁿ × (m + n)) Time and O(2ⁿ) Space

Generate all subsequences of s1 using bitmask. Check each subsequence if it exists in s2 using two-pointer subsequence check. Track the maximum length and collect all distinct subsequences of that length.

C++
// C++ program to find all distinct lcs
#include <iostream>
#include <vector>
#include <set>
using namespace std;

// check if t is a subsequence of s
bool isSubseq(string &t, string &s) {
    int i = 0, j = 0;
    while (i < t.size() && j < s.size()) {
        if (t[i] == s[j]) ++i;
        ++j;
    }
    return i == t.size();
}

vector<string> allLCS(string &s1, string &s2) {
    int n = s1.size();
    int best = 0;
    set<string> st;

    // iterate over all 2^n subsequences of s1
    for (int mask = 0; mask < (1<<n); ++mask) {
        string sub;
        for (int i = 0; i < n; ++i) {
            if (mask & (1<<i)) 
                sub.push_back(s1[i]);
        }
        int len = sub.size();
        
        // too short, skip
        if (len < best) 
            continue;             
        if (isSubseq(sub, s2)) {
            
            // found a longer length
            if (len > best) {
                best = len;
                st.clear();      
            }
            st.insert(sub);
        }
    }
    
    vector<string> ans;
    
    // move into a sorted vector
    for(auto i:st) ans.push_back(i);
    
    return ans;
}

int main() {
    string s1 = "abac";
    string s2 = "aabca";

    auto res = allLCS(s1, s2);
    
    cout << "[";
    for (int i = 0; i < res.size(); ++i) {
        cout << "\"" << res[i] << "\"";
        if (i+1 < res.size()) cout << ", ";
    }
    cout << "]\n";

    return 0;
}
Java
// Java program to find all distinct LCS
import java.util.*;

public class GfG {
    
    // check if t is a subsequence of s
    public static boolean isSubseq(String t, String s) {
        int i = 0, j = 0;
        while (i < t.length() && j < s.length()) {
            if (t.charAt(i) == s.charAt(j)) ++i;
            ++j;
        }
        return i == t.length();
    }

    // 
    public static ArrayList<String> allLCS(String s1, String s2) {
        int n = s1.length();
        int best = 0;
        Set<String> st = new HashSet<>();

        // iterate over all 2^n subsequences of s1
        for (int mask = 0; mask < (1 << n); ++mask) {
            StringBuilder sub = new StringBuilder();
            for (int i = 0; i < n; ++i) {
                if ((mask & (1 << i)) != 0) 
                    sub.append(s1.charAt(i));
            }
            int len = sub.length();
            if (len < best) 
                continue;              
            if (isSubseq(sub.toString(), s2)) {
                if (len > best) {
                    best = len;
                    st.clear();      
                }
                st.add(sub.toString());
            }
        }
        
        // build and sort 
        ArrayList<String> ans = new ArrayList<>(st);
        Collections.sort(ans);
        return ans;
    }

    public static void main(String[] args) {
        String s1 = "abac", s2 = "aabca";
        ArrayList<String> res = allLCS(s1, s2);
        
        System.out.print("[");
        for (int i = 0; i < res.size(); i++) {
            System.out.print('"' + res.get(i) + '"');
            if (i + 1 < res.size()) System.out.print(", ");
        }
        System.out.println("]");
    }
}
Python
# Python program to find all distinct LCS
from itertools import combinations

# check if t is a subsequence of s
def isSubseq(t, s):
    i = 0
    j = 0
    while i < len(t) and j < len(s):
        if t[i] == s[j]:
            i += 1
        j += 1
    return i == len(t)

def allLCS(s1, s2):
    n = len(s1)
    best = 0
    st = set()

    # iterate over all 2^n subsequences of s1
    for mask in range(1 << n):
        sub = ''.join(s1[i] for i in range(n) if mask & (1 << i))
        length = len(sub)
        
        # too short, skip
        if length < best:
            continue
        if isSubseq(sub, s2):
            
            # found a longer length
            if length > best:
                best = length
                st.clear()
            st.add(sub)
    
    ans = sorted(st)
    return ans

if __name__ == '__main__':
    s1 = "abac"
    s2 = "aabca"
    res = allLCS(s1, s2)
    
    print(res)
C#
// C# program to find all distinct LCS
using System;
using System.Collections.Generic;
using System.Linq;

class GfG {
    
    // check if t is a subsequence of s
    static bool isSubseq(string t, string s) {
        int i = 0, j = 0;
        while (i < t.Length && j < s.Length) {
            if (t[i] == s[j]) ++i;
            ++j;
        }
        return i == t.Length;
    }

    static List<string> allLCS(string s1, string s2) {
        int n = s1.Length;
        int best = 0;
        HashSet<string> st = new HashSet<string>();

        // iterate over all 2^n subsequences of s1
        for (int mask = 0; mask < (1 << n); ++mask) {
            string sub = "";
            for (int i = 0; i < n; ++i) {
                if ((mask & (1 << i)) != 0) 
                    sub += s1[i];
            }
            int len = sub.Length;
            
            // too short, skip
            if (len < best) 
                continue;              
            if (isSubseq(sub, s2)) {
                
                // found a longer length
                if (len > best) {
                    best = len;
                    st.Clear();      
                }
                st.Add(sub);
            }
        }
        
        List<string> ans = st.OrderBy(x => x).ToList();
        return ans;
    }

    static void Main() {
        string s1 = "abac", s2 = "aabca";
        var res = allLCS(s1, s2);
        
        Console.WriteLine("[" + string.Join(", ", res.Select(x => '"' + x + '"')) + "]");
    }
}
JavaScript
// JavaScript program to find all distinct LCS

// check if t is a subsequence of s
function isSubseq(t, s) {
    let i = 0, j = 0;
    while (i < t.length && j < s.length) {
        if (t[i] === s[j]) i++;
        j++;
    }
    return i === t.length;
}

function allLCS(s1, s2) {
    let n = s1.length;
    let best = 0;
    let st = new Set();

    // iterate over all 2^n subsequences of s1
    for (let mask = 0; mask < (1 << n); mask++) {
        let sub = '';
        for (let i = 0; i < n; i++) {
            if (mask & (1 << i)) 
                sub += s1[i];
        }
        let len = sub.length;
        
        // too short, skip
        if (len < best) 
            continue;
        if (isSubseq(sub, s2)) {
            
            // found a longer length
            if (len > best) {
                best = len;
                st.clear();
            }
            st.add(sub);
        }
    }
    
    let ans = Array.from(st).sort();
    return ans;
}

const s1 = 'abac';
const s2 = 'aabca';
const res = allLCS(s1, s2);

console.log('[' + res.map(x => '"' + x + '"').join(', ') + ']');

Output
["aac", "aba", "abc"]

[Expected Approach] DP with Backtracking - O(m × n + L × 26 × (m + n)) Time and O(m × n) Space

Compute LCS length using DP table. Then backtrack to construct all distinct LCS strings by trying characters from 'a' to 'z' at each step, ensuring lexicographic order and only following paths that lead to full LCS length.

  • Build DP table where dp[i][j] stores LCS length for s1[i..] and s2[j..]. The length of LCS is stored at dp[0][0]. Get lcsLen = dp[0][0]
  • Backtrack from (0,0) with empty current string. If current length becomes lcsLen, add to result
  • Try characters 'a' to 'z' in order. For each char, find next occurrence in s1 and s2 where dp[ii][jj] equals remaining length
  • Recurse with ii+1, jj+1 after adding char

Illustration:


C++
// C++ program to find all distinct lcs
#include <iostream>
#include <vector>
using namespace std;

// Compute length of LCS(s1, s2)
void lcsLength(string &s1, string &s2, vector<vector<int>> &dp) {
     int m=s1.size(),n=s2.size();
     for (int i = m - 1; i >= 0; --i) {
        for (int j = n - 1; j >= 0; --j) {
            if (s1[i] == s2[j])
                dp[i][j] = dp[i + 1][j + 1] + 1;
            else
                dp[i][j] = max(dp[i + 1][j], dp[i][j + 1]);
        }
    }

    // dp[0][0] contains length of LCS for s1[0..m-1]
    // and s2[0..n-1]
}

// Backtrack to collect all LCS strings of total length lcsLen
void backtrack(string &s1, string &s2, int i, int j, int lcsLen, 
        vector<vector<int>> &dp, string &cur, vector<string> &res) {
    if (cur.size() == lcsLen) {
        res.push_back(cur);
        return;
    }
    if (i == (int)s1.size() || j == (int)s2.size())
        return;
        
    int built = cur.size();

    // Try each character in 'a'..'z' to enforce lex order
    for (char ch = 'a'; ch <= 'z'; ++ch) {
        bool found = false;
        for (int ii = i; ii < (int)s1.size(); ++ii) {
            if (s1[ii] != ch) continue;
            for (int jj = j; jj < (int)s2.size(); ++jj) {
                if (s2[jj] == ch
                    && dp[ii][jj] == lcsLen - built)
                {
                    cur.push_back(ch);
                    backtrack(s1, s2, ii+1, jj+1, lcsLen, dp, cur, res);
                    cur.pop_back();
                    found = true;
                    break;
                }
            }
            if (found) break;
        }
    }
}

// Returns all distinct, lex-sorted LCS strings of s and t
vector<string> allLCS(string &s1, string &s2) {
    int n = s1.size(), m = s2.size();
    vector<vector<int>> dp(n+1, vector<int>(m+1));

    // Find length of LCS
    lcsLength(s1, s2, dp);
    
    int lcsLen = dp[0][0];
    
    // Backtrack to collect them
    vector<string> res;
    string cur;
    backtrack(s1, s2, 0, 0, lcsLen, dp, cur, res);

    return res;
}

int main() {
    string s1 = "abac";
    string s2 = "aabca";

    vector<string> res = allLCS(s1, s2);

    cout << "[";
    for (int i = 0; i < res.size(); ++i) {
        cout << "\"" << res[i] << "\"";
        if (i + 1 < res.size()) cout << ", ";
    }
    cout << "]\n";
    return 0;
}
Java
// Java program to find all distinct LCS strings

import java.util.*;

class GfG {

    // Compute LCS length table
    static void lcsLength(String s1, String s2, int[][] dp) {
        int n = s1.length();
        int m = s2.length();

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

                if (s1.charAt(i) == s2.charAt(j)) {
                    dp[i][j] = 1 + dp[i + 1][j + 1];
                } else {
                    dp[i][j] = Math.max(dp[i + 1][j], dp[i][j + 1]);
                }
            }
        }
    }

    // Backtrack to generate all LCS strings
    static void backtrack(String s1, String s2, int i, int j,
                          int lcsLen, int[][] dp,
                          StringBuilder curr,
                          ArrayList<String> res) {

        // One complete LCS is formed
        if (curr.length() == lcsLen) {
            res.add(curr.toString());
            return;
        }

        if (i == s1.length() || j == s2.length()) {
            return;
        }

        int built = curr.length();

        // Try characters from a-z to maintain lexicographical order
        for (char ch = 'a'; ch <= 'z'; ch++) {

            boolean found = false;

            for (int ii = i; ii < s1.length(); ii++) {

                if (s1.charAt(ii) != ch)
                    continue;

                for (int jj = j; jj < s2.length(); jj++) {

                    if (s2.charAt(jj) == ch &&
                        dp[ii][jj] == lcsLen - built) {

                        curr.append(ch);

                        backtrack(s1, s2,
                                  ii + 1, jj + 1,
                                  lcsLen, dp,
                                  curr, res);

                        curr.deleteCharAt(curr.length() - 1);

                        found = true;
                        break;
                    }
                }

                if (found)
                    break;
            }
        }
    }

    // Returns all distinct LCS strings
    static ArrayList<String> allLCS(String s1, String s2) {

        int n = s1.length();
        int m = s2.length();

        int[][] dp = new int[n + 1][m + 1];

        // Build LCS length table
        lcsLength(s1, s2, dp);

        int lcsLen = dp[0][0];

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

        StringBuilder curr = new StringBuilder();

        backtrack(s1, s2, 0, 0, lcsLen,
                  dp, curr, res);

        return res;
    }

    public static void main(String[] args) {

        String s1 = "abac";
        String s2 = "aabca";

        ArrayList<String> res = allLCS(s1, s2);

        System.out.print("[");

        for (int i = 0; i < res.size(); i++) {

            System.out.print("\"" + res.get(i) + "\"");

            if (i != res.size() - 1)
                System.out.print(", ");
        }

        System.out.println("]");
    }
}
Python
# Python program to find all distinct LCS strings

# Compute length of LCS(s1, s2)
def lcsLength(s1, s2, dp):
    m, n = len(s1), len(s2)
    
    for i in range(m - 1, -1, -1):
        for j in range(n - 1, -1, -1):
            if s1[i] == s2[j]:
                dp[i][j] = dp[i + 1][j + 1] + 1
            else:
                dp[i][j] = max(dp[i + 1][j], dp[i][j + 1])

# Backtrack to collect all LCS strings of total length lcsLen
def backtrack(s1, s2, i, j, lcsLen, dp, cur, res):
    if len(cur) == lcsLen:
        res.append(''.join(cur))
        return
    if i == len(s1) or j == len(s2):
        return
    
    built = len(cur)
    
    # Try each character in 'a'..'z' to enforce lex order
    for ch in range(ord('a'), ord('z') + 1):
        char = chr(ch)
        found = False
        for ii in range(i, len(s1)):
            if s1[ii] != char:
                continue
            for jj in range(j, len(s2)):
                if s2[jj] == char and dp[ii][jj] == lcsLen - built:
                    cur.append(char)
                    backtrack(s1, s2, ii + 1, jj + 1, lcsLen, dp, cur, res)
                    cur.pop()
                    found = True
                    break
            if found:
                break

# Returns all distinct, lex-sorted LCS strings of s and t
def allLCS(s1, s2):
    n, m = len(s1), len(s2)
    dp = [[0] * (m + 1) for _ in range(n + 1)]
    
    # Find length of LCS
    lcsLength(s1, s2, dp)
    
    lcsLen = dp[0][0]
    
    # Backtrack to collect them
    res = []
    cur = []
    backtrack(s1, s2, 0, 0, lcsLen, dp, cur, res)
    
    return res

# Driver code
if __name__ == "__main__":
    s1 = "abac"
    s2 = "aabca"
    
    res = allLCS(s1, s2)
    
    print("[", end="")
    for i in range(len(res)):
        print(f"\"{res[i]}\"", end="")
        if i + 1 < len(res):
            print(", ", end="")
    print("]")
C#
// C# program to find all distinct LCS strings
using System;
using System.Collections.Generic;
using System.Text;

class GfG {
    
    // Compute length of LCS(s1, s2)
    static void lcsLength(string s1, string s2, int[,] dp) {
        int m = s1.Length, n = s2.Length;
        
        for (int i = m - 1; i >= 0; i--) {
            for (int j = n - 1; j >= 0; j--) {
                if (s1[i] == s2[j])
                    dp[i, j] = dp[i + 1, j + 1] + 1;
                else
                    dp[i, j] = Math.Max(dp[i + 1, j], dp[i, j + 1]);
            }
        }
    }
    
    // Backtrack to collect all LCS strings of total length lcsLen
    static void backtrack(string s1, string s2, int i, int j, int lcsLen,
                          int[,] dp, StringBuilder cur, List<string> res) {
        if (cur.Length == lcsLen) {
            res.Add(cur.ToString());
            return;
        }
        if (i == s1.Length || j == s2.Length)
            return;
        
        int built = cur.Length;
        
        // Try each character in 'a'..'z' to enforce lex order
        for (char ch = 'a'; ch <= 'z'; ch++) {
            bool found = false;
            for (int ii = i; ii < s1.Length; ii++) {
                if (s1[ii] != ch) continue;
                for (int jj = j; jj < s2.Length; jj++) {
                    if (s2[jj] == ch && dp[ii, jj] == lcsLen - built) {
                        cur.Append(ch);
                        backtrack(s1, s2, ii + 1, jj + 1, lcsLen, dp, cur, res);
                        cur.Remove(cur.Length - 1, 1);
                        found = true;
                        break;
                    }
                }
                if (found) break;
            }
        }
    }
    
    // Returns all distinct, lex-sorted LCS strings of s and t
    static List<string> allLCS(string s1, string s2) {
        int n = s1.Length, m = s2.Length;
        int[,] dp = new int[n + 1, m + 1];
        
        // Find length of LCS
        lcsLength(s1, s2, dp);
        
        int lcsLen = dp[0, 0];
        
        // Backtrack to collect them
        List<string> res = new List<string>();
        StringBuilder cur = new StringBuilder();
        backtrack(s1, s2, 0, 0, lcsLen, dp, cur, res);
        
        return res;
    }
    
    static void Main(string[] args) {
        string s1 = "abac";
        string s2 = "aabca";
        
        List<string> res = allLCS(s1, s2);
        
        Console.Write("[");
        for (int i = 0; i < res.Count; i++) {
            Console.Write("\"" + res[i] + "\"");
            if (i + 1 < res.Count) Console.Write(", ");
        }
        Console.WriteLine("]");
    }
}
JavaScript
// JavaScript program to find all distinct LCS strings

// Compute length of LCS(s1, s2)
function lcsLength(s1, s2, dp) {
    const m = s1.length, n = s2.length;
    
    for (let i = m - 1; i >= 0; i--) {
        for (let j = n - 1; j >= 0; j--) {
            if (s1[i] === s2[j])
                dp[i][j] = dp[i + 1][j + 1] + 1;
            else
                dp[i][j] = Math.max(dp[i + 1][j], dp[i][j + 1]);
        }
    }
}

// Backtrack to collect all LCS strings of total length lcsLen
function backtrack(s1, s2, i, j, lcsLen, dp, cur, res) {
    if (cur.length === lcsLen) {
        res.push(cur.join(''));
        return;
    }
    if (i === s1.length || j === s2.length)
        return;
    
    const built = cur.length;
    
    // Try each character in 'a'..'z' to enforce lex order
    for (let chCode = 97; chCode <= 122; chCode++) {
        const ch = String.fromCharCode(chCode);
        let found = false;
        for (let ii = i; ii < s1.length; ii++) {
            if (s1[ii] !== ch) continue;
            for (let jj = j; jj < s2.length; jj++) {
                if (s2[jj] === ch && dp[ii][jj] === lcsLen - built) {
                    cur.push(ch);
                    backtrack(s1, s2, ii + 1, jj + 1, lcsLen, dp, cur, res);
                    cur.pop();
                    found = true;
                    break;
                }
            }
            if (found) break;
        }
    }
}

// Returns all distinct, lex-sorted LCS strings of s and t
function allLCS(s1, s2) {
    const n = s1.length, m = s2.length;
    const dp = Array(n + 1);
    for (let i = 0; i <= n; i++) {
        dp[i] = Array(m + 1).fill(0);
    }
    
    // Find length of LCS
    lcsLength(s1, s2, dp);
    
    const lcsLen = dp[0][0];
    
    // Backtrack to collect them
    const res = [];
    const cur = [];
    backtrack(s1, s2, 0, 0, lcsLen, dp, cur, res);
    
    return res;
}

// Driver code
const s1 = "abac";
const s2 = "aabca";

const res = allLCS(s1, s2);

console.log(JSON.stringify(res));

Output
["aac", "aba", "abc"]
Comment