📖 Scenario: You are working on a text comparison tool that helps find the longest common subsequence (LCS) between two strings. This is useful in version control systems to highlight changes between file versions.
🎯 Goal: Build a Rust program that calculates the length of the longest common subsequence between two given strings using dynamic programming.
📋 What You'll Learn
Create two string variables with exact values
Create a 2D vector to store LCS lengths
Use nested loops with exact variable names to fill the DP table
Print the final LCS length
💡 Why This Matters
🌍 Real World
Longest common subsequence is used in file comparison tools, DNA sequence analysis, and version control systems to find similarities between sequences.
💼 Career
Understanding dynamic programming and string algorithms is essential for software engineers working on text processing, bioinformatics, and data comparison tasks.
Progress0 / 4 steps
1
Create the two input strings
Create two string variables called string1 and string2 with the exact values "AGGTAB" and "GXTXAYB" respectively.
DSA Rust
Hint
Use let to create string slices with the exact text.
2
Initialize the DP table
Add code to create a 2D vector called dp with dimensions string1.len() + 1 by string2.len() + 1, filled with zeros of type usize.
DSA Rust
Hint
Use vec![value; size] to create vectors. Remember to make dp mutable.
3
Fill the DP table with LCS lengths
Use nested for loops with variables i and j to iterate from 1 to string1.len() and 1 to string2.len() respectively. Inside the loops, compare characters at string1.chars().nth(i - 1).unwrap() and string2.chars().nth(j - 1).unwrap(). If they match, set dp[i][j] = dp[i - 1][j - 1] + 1. Otherwise, set dp[i][j] = dp[i - 1][j].max(dp[i][j - 1]).
DSA Rust
Hint
Use ..= for inclusive ranges. Use chars().nth() with unwrap() to get characters.
4
Print the length of the longest common subsequence
Print the value at dp[string1.len()][string2.len()] using println! with the exact format: "Length of LCS is: {}".
DSA Rust
Hint
Use println!("Length of LCS is: {}", value) to print the result.
Practice
(1/5)
1. What does the Longest Common Subsequence (LCS) between two strings represent?
easy
A. The longest sequence of characters that appear in both strings in the same order, but not necessarily consecutively.
B. The longest substring that appears exactly the same in both strings.
C. The shortest sequence of characters that can be removed to make the strings identical.
D. The total number of characters that differ between the two strings.
Solution
Step 1: Understand the definition of LCS
The LCS is the longest sequence of characters that appear in both strings in the same order, but not necessarily consecutively.
Step 2: Differentiate from substring and other concepts
Unlike substring, LCS does not require characters to be consecutive. It is about order and presence.
Final Answer:
The longest sequence of characters that appear in both strings in the same order, but not necessarily consecutively. -> Option A
2. Which of the following Rust function signatures correctly represents a function to compute LCS length between two string slices?
easy
A. fn lcs_length(s1: &str, s2: &str) -> bool
B. fn lcs_length(s1: String, s2: String) -> &str
C. fn lcs_length(s1: &String, s2: &String) -> String
D. fn lcs_length(s1: &str, s2: &str) -> usize
Solution
Step 1: Identify correct parameter types for string inputs
Using &str is idiomatic for string slices in Rust, allowing borrowing without ownership transfer.
Step 2: Identify correct return type for LCS length
LCS length is a number, so usize is appropriate. Returning &str or String is incorrect for length.
Final Answer:
fn lcs_length(s1: &str, s2: &str) -> usize -> Option D
Quick Check:
Input: &str, Output: usize for length [OK]
Hint: Use &str for inputs and usize for length output [OK]
Common Mistakes:
Returning &str or String instead of length
Using owned String unnecessarily
Returning bool instead of length
3. What is the output of the following Rust code snippet that computes the LCS length of "AGGTAB" and "GXTXAYB"?
fn main() {
let s1 = "AGGTAB";
let s2 = "GXTXAYB";
let lcs_len = lcs_length(s1, s2);
println!("{}", lcs_len);
}
fn lcs_length(s1: &str, s2: &str) -> usize {
let m = s1.len();
let n = s2.len();
let mut dp = vec![vec![0; n + 1]; m + 1];
for i in 1..=m {
for j in 1..=n {
if s1.as_bytes()[i - 1] == s2.as_bytes()[j - 1] {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = dp[i - 1][j].max(dp[i][j - 1]);
}
}
}
dp[m][n]
}
medium
A. 6
B. 3
C. 4
D. 5
Solution
Step 1: Understand the input strings and LCS algorithm
Strings are "AGGTAB" and "GXTXAYB". The code uses dynamic programming to find LCS length.
Step 2: Trace the LCS calculation
The LCS is "GTAB" with length 4. The code correctly computes this.
Step 3: Verify carefully
Common subsequence: G T A B (positions match in order). Length is 4.
Final Answer:
4 -> Option C
Quick Check:
LCS length of "AGGTAB" and "GXTXAYB" = 4 [OK]
Hint: Trace matching chars in order, ignore gaps [OK]
Common Mistakes:
Counting common characters not in order
Confusing substring with subsequence
Off-by-one errors in indexing
4. Identify the bug in the following Rust function that attempts to compute the LCS length:
fn lcs_length(s1: &str, s2: &str) -> usize {
let m = s1.len();
let n = s2.len();
let mut dp = vec![vec![0; n]; m];
for i in 1..m {
for j in 1..n {
if s1.as_bytes()[i] == s2.as_bytes()[j] {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = dp[i - 1][j].max(dp[i][j - 1]);
}
}
}
dp[m - 1][n - 1]
}
medium
A. The dp vector is initialized with size m x n instead of (m+1) x (n+1).
B. The loops start from 0 instead of 1, causing index errors.
C. The loops use 1..=m and 1..=n instead of 1..m and 1..n, causing out of bounds.
D. The function returns dp[m][n] which is out of bounds.
Solution
Step 1: Check dp vector initialization
The dp vector is initialized as m x n, but it should be (m+1) x (n+1) to handle base cases and indexing from 1.
Step 2: Understand loop ranges and indexing
Loops start from 1..
Final Answer:
The dp vector is initialized with size m x n instead of (m+1) x (n+1). -> Option A
Quick Check:
dp size must be (m+1) x (n+1) [OK]
Hint: dp table size must include extra row and column [OK]
Common Mistakes:
Initializing dp with wrong size
Incorrect loop ranges causing panic
Wrong indexing of string bytes
5. Given two strings, write a Rust function that returns the actual Longest Common Subsequence string (not just length). Which approach below correctly reconstructs the LCS from the dp table?
hard
A. Start from dp[0][0], move right or down collecting characters whenever dp[i][j] increases.
B. Start from dp[m][n], move diagonally up-left if characters match, else move to the cell with the larger value, collecting matched characters in reverse order.
C. Traverse dp table row-wise and append characters when dp[i][j] is non-zero.
D. Reverse both strings and find LCS length, then reverse the result to get LCS string.
Solution
Step 1: Understand dp table usage for reconstruction
The dp table stores lengths of LCS for substrings. To reconstruct, start from dp[m][n] and move backwards.
Step 2: Trace path to build LCS string
If characters match at s1[i-1] and s2[j-1], move diagonally up-left and add character. Else move to cell with larger dp value (up or left).
Step 3: Reverse collected characters
Since traversal is from end to start, collected characters must be reversed to get correct LCS.
Final Answer:
Start from dp[m][n], move diagonally up-left if characters match, else move to the cell with the larger value, collecting matched characters in reverse order. -> Option B
Quick Check:
Backtrack dp table from bottom-right to reconstruct LCS [OK]
Hint: Backtrack dp from bottom-right, collect matches, then reverse [OK]
Common Mistakes:
Starting reconstruction from top-left
Not reversing collected characters
Ignoring dp values when moving
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.