Skip to content

Commit f3002c6

Browse files
committed
leetcode
1 parent 7a19142 commit f3002c6

File tree

4 files changed

+315
-0
lines changed

4 files changed

+315
-0
lines changed
+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
3+
4+
-* 1143. Longest Common Subsequence *-
5+
6+
7+
8+
Given two strings text1 and text2, return the length of their longest common subsequence. If there is no common subsequence, return 0.
9+
10+
A subsequence of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining characters.
11+
12+
For example, "ace" is a subsequence of "abcde".
13+
A common subsequence of two strings is a subsequence that is common to both strings.
14+
15+
16+
17+
Example 1:
18+
19+
Input: text1 = "abcde", text2 = "ace"
20+
Output: 3
21+
Explanation: The longest common subsequence is "ace" and its length is 3.
22+
Example 2:
23+
24+
Input: text1 = "abc", text2 = "abc"
25+
Output: 3
26+
Explanation: The longest common subsequence is "abc" and its length is 3.
27+
Example 3:
28+
29+
Input: text1 = "abc", text2 = "def"
30+
Output: 0
31+
Explanation: There is no such common subsequence, so the result is 0.
32+
33+
34+
Constraints:
35+
36+
1 <= text1.length, text2.length <= 1000
37+
text1 and text2 consist of only lowercase English characters.
38+
39+
40+
*/
41+
42+
import 'dart:math';
43+
44+
class A {
45+
// Complexity:
46+
// Time: O(mn), m is length of text1, n is length of text2
47+
// Space: O(mn) --> can be optimized to O(min(m, n)) since only accessing previous row
48+
int longestCommonSubsequence(String text1, String text2) {
49+
if (text1.length < text2.length) {
50+
return LCS(text1, text2);
51+
}
52+
return LCS(text2, text1);
53+
}
54+
55+
int LCS(String s1, String s2) {
56+
List<List<int>> M =
57+
List.filled(2, 0).map((e) => List.filled(s1.length + 1, 0)).toList();
58+
//row represents the length of s2, col represents the length of s1
59+
60+
for (int i = 1; i <= s2.length; i++) {
61+
//base case
62+
M[i % 2][0] = 0;
63+
for (int j = 1; j <= s1.length; j++) {
64+
if (s1[j - 1] == s2[i - 1]) {
65+
M[i % 2][j] = M[(i - 1) % 2][j - 1] + 1;
66+
} else {
67+
M[i % 2][j] = max(
68+
M[(i - 1) % 2][j - 1], max(M[(i - 1) % 2][j], M[i % 2][j - 1]));
69+
}
70+
}
71+
}
72+
return M[s2.length % 2][s1.length];
73+
}
74+
}
75+
76+
class B {
77+
// m*n time O(n) space
78+
int longestCommonSubsequence(String text1, String text2) {
79+
if (text1.length == 0 || text2.length == 0) return 0;
80+
int m = text1.length, n = text2.length;
81+
List<List<int>> dp =
82+
List.filled(2, 0).map((e) => List.filled(n + 1, 0)).toList();
83+
for (int i = 1; i <= m; i++) {
84+
for (int j = 1; j <= n; j++) {
85+
if (text1[i - 1] == text2[j - 1]) {
86+
dp[i % 2][j] = dp[(i - 1) % 2][j - 1] + 1;
87+
} else {
88+
dp[i % 2][j] = max(dp[i % 2][j - 1], dp[(i - 1) % 2][j]);
89+
}
90+
}
91+
}
92+
return dp[m % 2][n];
93+
}
94+
}
95+
96+
class C {
97+
// s = text1
98+
// t = text2
99+
int longestCommonSubsequence(String text1, String text2) {
100+
int n = text1.length;
101+
int m = text2.length;
102+
103+
List<List<int>> dp =
104+
List.filled(n + 1, 0).map((e) => List.filled(m + 1, 0)).toList();
105+
if (text1[0] == text2[0]) {
106+
dp[0][0] = 1;
107+
} else {
108+
dp[0][0] = 0;
109+
}
110+
for (int i = 1; i < n; i++) {
111+
if (text1[i] == text2[0]) {
112+
dp[i][0] = 1;
113+
} else {
114+
dp[i][0] = dp[i - 1][0];
115+
}
116+
}
117+
for (int i = 1; i < m; i++) {
118+
if (text1[0] == text2[i]) {
119+
dp[0][i] = 1;
120+
} else {
121+
dp[0][i] = dp[0][i - 1];
122+
}
123+
}
124+
for (int i = 1; i < n; i++) {
125+
for (int j = 1; j < m; j++) {
126+
if (text1[i] == text2[j]) {
127+
dp[i][j] = 1 + dp[i - 1][j - 1];
128+
} else {
129+
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
130+
}
131+
}
132+
}
133+
return dp[n - 1][m - 1];
134+
}
135+
}
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package main
2+
3+
func longestCommonSubsequence(text1 string, text2 string) int {
4+
len1 := len(text1)
5+
len2 := len(text2)
6+
dp := make([][]int, len1+1)
7+
for i := range dp {
8+
dp[i] = make([]int, len2+1)
9+
}
10+
for i := 1; i <= len1; i++ {
11+
for j := 1; j <= len2; j++ {
12+
if text1[i-1] == text2[j-1] {
13+
dp[i][j] = dp[i-1][j-1] + 1
14+
} else {
15+
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
16+
}
17+
}
18+
}
19+
return dp[len1][len2]
20+
}
21+
22+
func max(a, b int) int {
23+
if a > b {
24+
return a
25+
}
26+
return b
27+
}
+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# 🔥 Longest Common Subsequence 🔥 || 3 Approaches || Simple Fast and Easy || with Explanation
2+
3+
## Explanation
4+
5+
The general DP algorithm is to consider a grid of width len(text1) and height len(text2).
6+
7+
```dart
8+
t e n s
9+
t +---+---+---+---+
10+
| \ | \ | \ | \ |
11+
h +---+---+---+---+
12+
| \ | \ | \ | \ |
13+
e +---+---+---+---+
14+
| \ | \ | \ | \ |
15+
+---+---+---+---+
16+
```
17+
18+
Each column is associated to a letter in text1.
19+
Each row is associated to a letter in text2.
20+
Here, you can see an example with "tens" and "the".
21+
22+
The goal is to find the longest path from the top-left corner the the bottom right corner by going always down or right or diagonally.
23+
Going right means "not taking a letter from text1". So, it counts as an edge of length 0 in the paths.
24+
Going down means "not taking a letter from text2". So, it counts as an edge of length 0 in the paths.
25+
Going diagonally (down-right) is only possible for two identical letters. It means "taking a letter in both texts". So, it counts as an edge of length 1 in the paths.
26+
27+
Here's the solution for the previous example.
28+
29+
```dart
30+
t e n s
31+
t +
32+
\
33+
h +
34+
|
35+
e +
36+
\
37+
+---+---+
38+
```
39+
40+
This corresponds to "te" (diagonal links), the LCS of size 2.
41+
42+
My solution uses only O(n) memory. It relies on the fact that each value on a line can be computed with the current and previous line.
43+
If we wanted the whole subsequence, we would need to keep the whole grid. for backtracking. But since we are only interested in the length of the LCS, two lines is all we need.
44+
45+
## Solution - 1
46+
47+
### Complexity
48+
49+
- Time: O(mn), m is length of text1, n is length of text2
50+
- Space: O(mn) --> can be optimized to O(min(m, n)) since only accessing previous row
51+
52+
```dart
53+
class Solution {
54+
int longestCommonSubsequence(String text1, String text2) {
55+
if (text1.length < text2.length) {
56+
return LCS(text1, text2);
57+
}
58+
return LCS(text2, text1);
59+
}
60+
61+
int LCS(String s1, String s2) {
62+
List<List<int>> M =
63+
List.filled(2, 0).map((e) => List.filled(s1.length + 1, 0)).toList();
64+
//row represents the length of s2, col represents the length of s1
65+
66+
for (int i = 1; i <= s2.length; i++) {
67+
//base case
68+
M[i % 2][0] = 0;
69+
for (int j = 1; j <= s1.length; j++) {
70+
if (s1[j - 1] == s2[i - 1]) {
71+
M[i % 2][j] = M[(i - 1) % 2][j - 1] + 1;
72+
} else {
73+
M[i % 2][j] = max(
74+
M[(i - 1) % 2][j - 1], max(M[(i - 1) % 2][j], M[i % 2][j - 1]));
75+
}
76+
}
77+
}
78+
return M[s2.length % 2][s1.length];
79+
}
80+
}
81+
```
82+
83+
## Solution - 2
84+
85+
### Complexity
86+
87+
- Time: O(m*n),
88+
- Space: O(n)
89+
90+
```dart
91+
class Solution {
92+
int longestCommonSubsequence(String text1, String text2) {
93+
if (text1.length == 0 || text2.length == 0) return 0;
94+
int m = text1.length, n = text2.length;
95+
List<List<int>> dp =
96+
List.filled(2, 0).map((e) => List.filled(n + 1, 0)).toList();
97+
for (int i = 1; i <= m; i++) {
98+
for (int j = 1; j <= n; j++) {
99+
if (text1[i - 1] == text2[j - 1]) {
100+
dp[i % 2][j] = dp[(i - 1) % 2][j - 1] + 1;
101+
} else {
102+
dp[i % 2][j] = max(dp[i % 2][j - 1], dp[(i - 1) % 2][j]);
103+
}
104+
}
105+
}
106+
return dp[m % 2][n];
107+
}
108+
}
109+
```
110+
111+
## Solution - 3 - Optimized with One more LOOP
112+
113+
```dart
114+
class Solution {
115+
int longestCommonSubsequence(String text1, String text2) {
116+
int n = text1.length;
117+
int m = text2.length;
118+
119+
List<List<int>> dp =
120+
List.filled(n + 1, 0).map((e) => List.filled(m + 1, 0)).toList();
121+
if (text1[0] == text2[0]) {
122+
dp[0][0] = 1;
123+
} else {
124+
dp[0][0] = 0;
125+
}
126+
for (int i = 1; i < n; i++) {
127+
if (text1[i] == text2[0]) {
128+
dp[i][0] = 1;
129+
} else {
130+
dp[i][0] = dp[i - 1][0];
131+
}
132+
}
133+
for (int i = 1; i < m; i++) {
134+
if (text1[0] == text2[i]) {
135+
dp[0][i] = 1;
136+
} else {
137+
dp[0][i] = dp[0][i - 1];
138+
}
139+
}
140+
for (int i = 1; i < n; i++) {
141+
for (int j = 1; j < m; j++) {
142+
if (text1[i] == text2[j]) {
143+
dp[i][j] = 1 + dp[i - 1][j - 1];
144+
} else {
145+
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
146+
}
147+
}
148+
}
149+
return dp[n - 1][m - 1];
150+
}
151+
}
152+
```

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ This repo contain leetcode solution using DART and GO programming language. Most
167167
- [**124.** Binary Tree Maximum Path Sum](BinaryTreeMaximumPathSum/binary_tree_maximum_path_sum.dart)
168168
- [**931.** Minimum Falling Path Sum](MinimumFallingPathSum/minimum_falling_path_sum.dart)
169169
- [**198.** House Robber](HouseRobber/house_robber.dart)
170+
- [**1143.** Longest Common Subsequence](LongestCommonSubsequence/longest_common_subsequence.dart)
170171

171172
## Reach me via
172173

0 commit comments

Comments
 (0)