Minimum Insertions / Deletions to Convert String
Solve this ProblemTest Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
0 ≤ s1.length, s2.length ≤ 12 - ◆
s1 and s2 consist of lowercase English letters
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Brute Force — Recursive Longest Common Subsequence
BruteWhatever the longest common subsequence of s1 and s2 turns out to be, it never needs to move — it's already sitting in the right relative order in both strings. Every character of s1 outside that shared subsequence has no counterpart, so it must be deleted; every character of s2 outside it has nothing to line up with in s1, so it must be inserted. That means the total operations needed is just (s1's length − LCS length) + (s2's length − LCS length). Finding the LCS length recursively is the classic two-pointer walk from the ends of both strings: if the trailing characters match, both belong to the subsequence and the search shrinks by one on each side; otherwise try dropping the trailing character of either string and keep the better result. Without caching, the same (i, j) pair gets resolved from scratch through every path that reaches it, so the work doubles with each extra character.
O(2ⁿ⁺ᵐ)O(n + m)1class Solution {
2 private String s1, s2;
3 public int minOperations(String s1, String s2) {
4 this.s1 = s1;
5 this.s2 = s2;
6 int lcs = solve(s1.length(), s2.length());
7 return (s1.length() - lcs) + (s2.length() - lcs);
8 }
9 private int solve(int i, int j) {
10 if (i == 0 || j == 0) return 0;
11 if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
12 return 1 + solve(i - 1, j - 1);
13 }
14 return Math.max(solve(i - 1, j), solve(i, j - 1));
15 }
16}Optimal — Bottom-Up LCS Table
OptimalBuild the LCS length table bottom-up instead of re-deriving each (i, j) pair from scratch. dp[i][j] holds the LCS length between the first i characters of s1 and the first j characters of s2. Row 0 and column 0 stay 0 (an empty prefix shares nothing). Filling left to right, top to bottom: if the current characters match, dp[i][j] is one more than the diagonal neighbor dp[i-1][j-1]; otherwise it's the better of dropping the current character of s1 (dp[i-1][j]) or of s2 (dp[i][j-1]), both already computed. Once dp[n][m] holds the full LCS length, the same delete/insert formula from the brute force gives the answer directly.
O(n·m)O(n·m)1class Solution {
2 public int minOperations(String s1, String s2) {
3 int n = s1.length(), m = s2.length();
4 int[][] dp = new int[n + 1][m + 1];
5 for (int i = 1; i <= n; i++) {
6 for (int j = 1; j <= m; j++) {
7 if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
8 dp[i][j] = dp[i - 1][j - 1] + 1;
9 } else {
10 dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
11 }
12 }
13 }
14 int lcs = dp[n][m];
15 return (n - lcs) + (m - lcs);
16 }
17}