Minimum Window Subsequence

LeetCode problem 727. Minimum Window Subsequence.

## Problem description

Given strings `s1` and `s2`, return *the minimum contiguous substring part of* `s1`*, so that* `s2` *is a subsequence of the part*.

If there is no such window in `s1` that covers all characters in `s2`, return the empty string `""`. If there are multiple such minimum-length windows, return the one with the **left-most starting index**.

Example 1
**Input:** `s1 = "abcdebdde", s2 = "bde"`
**Output:** `"bcde"`
**Explanation:**
* `"bcde"` is the answer because it occurs before `"bdde"` which has the same length.
* `"deb"` is not a smaller window because the elements of `s2` in the window must occur in order.

Example 2
**Input:** `s1 = "jmeqksfrsdcmsiwvaovztaqenprpvnbstl", s2 = "u"`
**Output:** `""`
Constraints
* `1 <= s1.length <= 2 * 104`
* `1 <= s2.length <= 100`
* `s1` and `s2` consist of lowercase English letters.

## Analysis

Hint
Let `dp[j][e] = s` be the largest index for which `s1[s:e+1]` has `s2[0:j]` as a subsequence.
Here the start index is inclusive, and the end index is exclusive.
Let `len1` and `len2` be the length of `s1` and `s2` respectively. So we can see the ranges of *j*, *e* and *s*:

* 0 ≤ *j* ≤ `len2`
* 0 ≤ *e* < `len1`
* 0 ≤ *s* ≤ *e* + 1 ≤ `len1`

Then we can create the `dp` table with `(len2 + 1)` rows and `len1` columns. Each row corresponds to a *j*, and each column corresponds to an *e*. The table is filled up as follows:

* Initialize all cells with -1 (assuming that no match was found).
* Fill row 0 with values 1, 2, …, `len1`. This is because `s1[1:1]`, `s1[2:2]`, `s1[3:3]`, … are all empty strings, which automatically contain the substring `""` in `s2`.
* For `dp[1][0]`: This cell will contain 0 if `s2[1]` and `s1[0]` are the same character, or -1 otherwise.
* For all other cells:
	+ Starting from row 2, the first `j-1` columns are untouched (filled with -1), meaning that the substring `s1[0:e+1]` is too short to contain `s2[0:j]`.
	+ Transition equations are as follows: `dp[j][e] =`
		- `dp[j-1][e-1]`, if `s1[e] == s2[j-1]` (one new matching is found);
		- `dp[j][e-1]`, otherwise.

Finally there is a post-processing step. We will traverse through row `len2` of the `dp` table, and find the substring window with minimum length and minimum starting position.

* `dp[len2][e] == -1` means that there is no substring in `s1` ending at position *e* that will contain the entire `s2` as a subsequence.
* `dp[len2][e] >= 0` means that `dp[len2][e]` is the maximum starting index such that `s1[dp[len2][e]:e+1]` contains `s2` as a subsequence. In this case the length is `len = e - dp[len2][e] + 1`. We can traverse the bottom row from left to right to find out which length is the smallest, and for the smallest length which index is the earliest possible index for the result.

### Working example

Input
`s1 = "abadebdde"` (9 characters), `s2 = "abe"` (3 characters)
Filling up the `dp` table

* Lime cells: matching positions

Post-processing
Initialize: `minLen = INT_MAX`, `start = -1`.

Iterating over row 3 of the `dp` table

Output
`s1[0:5]`, i.e. `"abade"`.
### Complexity analysis

Space complexity
Let `len1` and `len2` be the length of `s1` and `s2` respectively. The `dp` table has (`len2` + 1) × `len1` total cells. So the total space complexity is **O(`len2` × `len1`)**.
Time complexity
To fill in the cells in the `dp` table, each cell takes O(1) computation. So total time complexity is **O(`len2` × `len1`)**.
## Solution

### C++ solution

```
class Solution {
public:
 std::string minWindow(std::string& s1, std::string& s2) {
 const int len1 = s1.length(), len2 = s2.length();
 if (len1 < len2) {
 return "";
 }

 // create dp table
 // Let dp[j][e] = s be the largest index for which S[s:e+1] has T[0:j] as a substring
 // start index is inclusive; ending index is exclusive
 // range of j: [0..len2]
 // range of e: [0..len1-1]
 // range of s: [0..len1]
 int dp[len2+1][len1];
 memset(dp, -1, sizeof dp);

 // fill in top row
 for (int e = 0; e < len1; ++e) {
 dp[0][e] = e + 1;
 }
 // other rows
 for (int j = 1; j <= len2; ++j) {
 for (int e = j - 1; e < len1; ++e) {
 if (e == 0) {
 // base case: process first character in both strings
 dp[j][e] = (s1[e] == s2[j-1]) ? 0 : -1;
 }
 else {
 dp[j][e] = (s1[e] == s2[j-1]) ? dp[j-1][e-1] // s1[e] and s2[j-1] match
 : dp[j][e-1]; // s1[e] and s2[j-1] do not match
 }
 }
 }

 // post-processing: find minimum window length
 int minLen = INT\_MAX, start = -1;
 for (int e = 0; e < len1; ++e) {
 if (dp[len2][e] > -1) {
 int len = e - dp[len2][e] + 1;
 if (len < minLen) {
 minLen = len;
 start = dp[len2][e];
 }
 }
 }
 return (start > -1) ? s1.substr(start, minLen) : "";
 }
};

```

### Java solution

```
class Solution {
 public String minWindow(String s1, String s2) {
 final int len1 = s1.length(), len2 = s2.length();
 if (len1 < len2) {
 return "";
 }

 // create dp table
 // Let dp[j][e] = s be the largest index for which S[s:e+1] has T[0:j] as a substring
 // start index is inclusive; ending index is exclusive
 // range of j: [0..len2]
 // range of e: [0..len1-1]
 // range of s: [0..len1]
 int[][] dp = new int[len2+1][len1];
 for (int[] row: dp) {
 Arrays.fill(row, -1);
 }

 // fill in top row
 for (int e = 0; e < len1; ++e) {
 dp[0][e] = e + 1;
 }
 // other rows
 for (int j = 1; j <= len2; ++j) {
 for (int e = j - 1; e < len1; ++e) {
 if (e == 0) {
 // base case: process first character in both strings
 dp[j][e] = (s1.charAt(e) == s2.charAt(j-1)) ? 0 : -1;
 }
 else {
 dp[j][e] = (s1.charAt(e) == s2.charAt(j-1))
 ? dp[j-1][e-1] // s1[e] and s2[j-1] match
 : dp[j][e-1]; // s1[e] and s2[j-1] do not match
 }
 }
 }

 // post-processing: find minimum window length
 int minLen = Integer.MAX\_VALUE, start = -1;
 for (int e = 0; e < len1; ++e) {
 if (dp[len2][e] > -1) {
 int len = e - dp[len2][e] + 1;
 if (len < minLen) {
 minLen = len;
 start = dp[len2][e];
 }
 }
 }
 return (start > -1) ? s1.substring(start, start + minLen) : "";
 }
}

```

## See also

* Minimum Window Substring
* Longest Common Subsequence
* Minimum Insertion Steps to Make a String Palindrome