Skip to content

Commit c1ecb25

Browse files
authored
Add files via upload
1 parent 625e96d commit c1ecb25

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
//GFG - https://www.geeksforgeeks.org/longest-common-subsequence-dp-4/
2+
//TechieDelight - https://www.techiedelight.com/longest-common-subsequence/
3+
4+
/*
5+
LCS is the problem of finding longest common subsequence that is present in given two seqeunces in the SAME ORDER.
6+
ie. Find the longest seqeunce which can be obtained from the first original sequence by DELETING some items and from the second original sequence by deleting other items.
7+
example -
8+
X : ABCBDAB
9+
Y : BDCABA
10+
Length of LCS is 4. LCS are BDAB, BCAB, BCBA
11+
NAIVE APPROACH
12+
check if all subsequence of X[1...n] are also a subsequence of Y[1...m].
13+
Number of subsequences of length 1 = nC1
14+
Number of subsequences of length 2 = nC2
15+
.
16+
.
17+
.
18+
Number of subsequences of length n = nCn
19+
We know, nC0 + nC1 + .... + nCn = 2^n
20+
number of subsquences of length ATLEAST 1 AND ATMOST n = (2^n)-1
21+
Time required of check if a subsequence is also a subsequence of Y = m
22+
Time Complexity of Naive Approach = O(n*(2^n))
23+
RECURSIVE APPROACH - uses Optimal Substructure Property
24+
We will be traversing the strings backwards ==> considering their PREFIXES
25+
We can see, to compute LCS(X[1...n],Y[1...m]) 2 cases arise -
26+
1. X[1...n],Y[1...m] end in same element ie, x[n] == Y[m]
27+
LCS(X[1...n],Y[1...m]) = LCS(X[1...n-1],Y[1...m-1]) + (X[n] or Y[m])
28+
29+
2. X[1...n],Y[1...m] do not end in same element ie, x[n] != Y[m]
30+
LCS(X[1...n],Y[1...m]) = max {LCS(X[1...n-1],Y[1...m]), LCS(X[1...n],Y[1...m-1])}
31+
Understand this property with example -
32+
X : ABCBDAB
33+
Y : BDCABA
34+
The LCS of the two sequences either ends with B or does not.
35+
Case 1: If LCS ends with B, it can not end with A and so we can remove A from Y, so the problem becomes LCS(X[1...n],Y[1...m-1])
36+
Case 2: If LCS does not end with B, we can remove B from X, so the problem becomes LCS(X[1...n-1],Y[1...m])
37+
*/
38+
39+
//Recursive Solution
40+
41+
public int LCSlength(String a, String b, int n, int m){
42+
if(n==0 || m==0) return 0;
43+
//+1 is for the current match of characters
44+
if(a.charAt(n-1)==b.charAt(m-1)) return LCSlength(a,b,n-1,m-1) + 1;
45+
46+
return Math.max(LCSlength(a,b,n,m-1),LCSlength(a,b,n-1,m));
47+
}
48+
/*
49+
Worst Case Time Complexity of the above solution is = O(2^(m+n))
50+
Worst Case is when there is NO common character in the two sequences.
51+
example - X : AAAA and Y : BBBBBB
52+
In the recursive solution, some subproblems are computed again ==> OVERLAPPING SUBPROBLEMS ==> DP CAN BE USED!
53+
*/
54+
55+
56+
//MEMOIZED RECURSIVE APPROACH - TOP DOWN APPROACH
57+
/*Top Down approach - Breaking Bigger problem into smaller subproblem and calculate and store the result in case it is needed in future*/
58+
class LCS{
59+
HashMap<String,Integer> map = new HashMap<String,Integer>();
60+
61+
public int LCSlength(String a, String b, int n, int m){
62+
if(n==0 || m==0) return 0;
63+
64+
String key = n+"|"+m;
65+
if(!map.containsKey(key)){
66+
if(a.charAt(n-1)==b.charAt(m-1)) map.put(key, LCSlength(a,b,n-1,m-1)+1);
67+
68+
else map.put(key, Math.max(LCSlength(a,b,n,m-1),LCSlength(a,b,n-1,m)));
69+
}
70+
71+
return map.get(key);
72+
}
73+
}
74+
75+
/*
76+
Time Complexity - O(n*m)
77+
Number of unique subproblems = n*m
78+
Other redundant recursive calls take constant time
79+
Space Complexity - O(n*m)
80+
*/
81+
82+
//BOTTOM-UP APPROACH
83+
/*Calculate smaller value first and work towards the bigger problem.*/
84+
class LCS{
85+
public int LCSlength(String a, String b, int n, int m){
86+
int lcs[][] = new int[n+1][m+1];
87+
88+
//first column of all rows is 0
89+
for(int i=0;i<=n;i++) lcs[i][0] = 0;
90+
//first row of all coumns is 0
91+
for(int j=0;j<=m;j++) lcs[0][j] = 0;
92+
93+
for(int i=1;i<=n;i++){
94+
for(int j=1;j<=m;j++){
95+
/*
96+
when a[i]==b[j], we can simply look for the last answer and add one to it.
97+
One is added to reflect that the current pair of characters are a match.
98+
last answer is found by not considering the current elements ie. going to the upper dioagnal cell
99+
*/
100+
if(a.charAt(i-1)==b.charAt(j-1)){
101+
lcs[i][j] = lcs[i-1][j-1]+1;
102+
}
103+
104+
/*
105+
when a[i]!=b[j],
106+
We can discard one character at a time from both the sequence to see if there is a match or not.
107+
let us assume,
108+
Sequence after dropping the last character = oldSeq
109+
Sequence kept as it is ie. Sequence which includes the current character = newSeq
110+
111+
Since we have added a new character in the newSeq, there is a possibilty that the last character of oldSeq matches the newly added last char of newSeq.
112+
*/
113+
else{
114+
lcs[i][j] = Math.max(lcs[i-1][j], lcs[i][j-1]);
115+
}
116+
}
117+
}
118+
119+
return lcs[n][m];
120+
}
121+
}
122+
/*
123+
Time Complexity -
124+
We are computing each of the (n*m) subproblems = O(n*m)
125+
Space Complexity -
126+
Storing results of all subproblems = O(n*m)
127+
*/

0 commit comments

Comments
 (0)