Search code examples
algorithmtime-complexityanalysislcs

Brute Force Approach for LCS and its Time Complexity [O(m*n)!?]


I have read several Algorithm books where it is been told brute force approach of Longest Common Subsequence takes 2^n which is exponential in time complexity. Whereas, I've noticed that while I am applying my brute force technique it's taking O(mn) (from my personal observation). I would like to request you please read my approach clearly and visualize in mind and ask question for further clarification if needed. My Approach is following:- Say we have two strings s1 = "ECDGI" , s2 = "ABCDEFGHIJ". Now what I am doing is I chose either one of the given strings. For say, s1. for i = 1 to n (n is the last index of s1), I am taking each value and comparing with the s2 in such a way that for a single character of s1 I am checking with all the characters of s2. Mathematically, ith value is checking through all jth value up to m (m is the last index of s2). Here, if I find any common character I just move to next character from both strings. Then just compute subsequence. I compute all the possible subsequence for each characters from s1 by running n loops. Finally, I compute the largest value. From my understanding it's taking O(mn) time complexity overall. So My Question is, " Is my Time Complexity Calculation right ? "

Trace :

i = 1, value = E, lcs = 3 [EGI]

i = 2, value = C, lcs = 4 [CDGI]

i = 3, value = D, lcs = 3 [DGI]

i = 4, value = G, lcs = 2 [GI]

i = 5, value = I, lcs = 1 [I]

Answer is = 4 (maximum lcs)

My code is given below !

import java.util.*;
public class Main {
      static int count;
      static String s1 = "ECDGI"; // you can try with "EEE" or etc. 
      static String s2 = "ABCDEFGHIJ"; // you can try with "EEE" or etc.
  public static void main(String[] args) {
 LinkedList<Integer> ll = new LinkedList<>();
      for(int i =0; i<s1.length();i++){
      int t = i;
      count = 0; 
       for (int j=0; j<s2.length();j++){
         if(s1.charAt(t)==s2.charAt(j)){
           count++; 
            doIt(t+1,j+1);
            break ; 
        }
       }
        ll.add(count);
      }
      System.out.println(ll); // printing the whole LinkedList
      System.out.println(Collections.max(ll)); // taking the maximum value 
  }
  public static void doIt(int a, int b){
 for ( ; a<s1.length(); a++){
        int t = b ; 
        for (; t<s2.length(); t++){
          if (s1.charAt(a) == s2.charAt(t)){
           count++; 
           b=t+1; 
           break ; 
           }
        }
     }
  }

}

Solution

    1. Your algorithm is wrong. Consider the case when s1 = "AABAA" and s2 = "AAAAB", your code gives 3, but LCS is 4.

    2. Time complexity is O(n * m * (n+m))

      • Why?

      • Well let`s consider worst case where we have s1 is n/2 'A' characters and n/2 'B' characters, and s2 is m/2 'A' characters and m/2 'C' characters

      • Now if we ignore doIt() function loops themselves give O(n * m)
      • So how many times doIt() is called? well for all pairs of n/2 first characters of s1 and m/2 of s2 so n/2 * m/2 times, or if we drop constants O(n * m ) times
      • Now lets analyze complexity of doIt()
      • It Uses something like 2 pointers to pass both strings so its complexity is O(n+m)
      • So total complexity is O(n * m * (n+m)) or O(n^2 * m + m^2 * n)