Subsequence With the Minimum Score — Problem & Solution
Subsequence With the Minimum Score solution explained: step-by-step approach, complexity and code in Python, Java, C++ and JavaScript. A hard problem.
Subsequence With the Minimum Score is a hard coding problem on strings, binary search and two pointers, asked in Amazon and Google interviews.
- Difficulty: Hard
- Topics: Strings, Binary Search, Two Pointers
- Asked at: Amazon, Google
- Time limit: 2 s
- Memory limit: 256 MB
- Languages: JavaScript, TypeScript, Python, Java, C++, C, C#, Go, Kotlin, Swift, Rust, PHP and Ruby
Problem statement
You are given two strings s and t. You may delete any number of characters from t (possibly none). Afterwards, the remaining t must be a subsequence of s (obtainable from s by deleting characters without reordering).
The score of a deletion is:
0if nothing is deleted;- otherwise
right - left + 1, whereleftandrightare the smallest and largest indices intof the deleted characters.
Return the minimum possible score that makes t a subsequence of s.
Example 1
Input: s = "kairo", t = "kxro"
Output: 1
Explanation: Delete `x` (index 1); `kro` is a subsequence of `kairo`.
Example 2
Input: s = "code", t = "duel"
Output: 3
Explanation: Neither `u` nor `l` occurs in `s`, so both must go; deleting indices 1..3 leaves `d`.
Example 3
Input: s = "streak", t = "sea"
Output: 0
Explanation: `sea` is already a subsequence of `streak`.
Constraints
1 <= s.length, t.length <= 10^5s and t consist of lowercase English letters
Hints for Subsequence With the Minimum Score
Hint 1
Only
leftandrightmatter for the score, so if you delete anything you may as well delete the whole blockt[left..right]. The task becomes: keep a prefix and a suffix oftand make their concatenation a subsequence ofs.Hint 2
Match prefixes greedily from the left of
s(as early as possible) and suffixes greedily from the right ofs(as late as possible). Record, for every suffix startk, the latest index ofswhere matchingt[k..]can begin.Hint 3
For each prefix length, the prefix ends at some position of
s; the best suffix is the longest one whose recorded start lies after that position. Both move monotonically, so a two-pointer sweep finds the best block in linear time.
How to solve Subsequence With the Minimum Score
Deleting a contiguous block of t is always optimal, so the answer is the shortest block whose removal leaves prefix + suffix as a subsequence of s. Greedy matching from both ends tells, for every prefix, how far into s it reaches, and for every suffix, how late in s it can start.
Approach
- Compute
suf[k]for the suffixest[k..]: scansfrom the right, matchingtfrom its end;suf[k]is the index inswheret[k]gets matched. Letfirstbe the smallestkthat can be matched this way (suf[m] = nfor the empty suffix). - If
first == 0,tis already a subsequence: return 0. Otherwise start withans = first(delete the prefixt[0..first-1]). - Sweep the prefix: match
t[0], t[1], …greedily from the left ofs, withqthe position just after the last matched character. Stop when a character cannot be matched. - After matching
t[0..i], advance a pointerk(never belowmax(first, i + 1)) untilsuf[k] >= q; the blockt[i+1..k-1]is deletable, soans = min(ans, k - i - 1). - Return
ans.
Why it works
If the deleted indices span [left, right], deleting everything in between too keeps the remainder a subsequence and does not change the score — so blocks suffice. A prefix and a suffix can be matched disjointly exactly when the earliest end of the prefix comes before the latest start of the suffix, which is what suf[k] >= q tests. Earliest-left and latest-right greedy matches are optimal for these two questions, and since q only grows and suf is increasing in k, the pointer k never has to move back.
Complexity
- Time —
O(|s| + |t|) - Space —
O(|t|)
Pitfalls
- Trying every block with a fresh subsequence check is
O(|t|^2 · |s|). - The answer
0(nothing deleted) is different from deleting one character — check whethertis already a subsequence first. - Do not read
suf[k]fork < first: those suffixes cannot be matched at all.
Reference solution
Python
def minimumScore(s: str, t: str) -> int:
n, m = len(s), len(t)
suf = [n] * (m + 1)
p = n - 1
j = m - 1
while j >= 0:
while p >= 0 and s[p] != t[j]:
p -= 1
if p < 0:
break
suf[j] = p
p -= 1
j -= 1
first = j + 1
if first == 0:
return 0
ans = first
q = 0
k = first
for i in range(m):
while q < n and s[q] != t[i]:
q += 1
if q == n:
break
q += 1
if k <= i:
k = i + 1
while k < m and suf[k] < q:
k += 1
ans = min(ans, k - i - 1)
return ansJava
public static int minimumScore(String s, String t) {
int n = s.length(), m = t.length();
int[] suf = new int[m + 1];
Arrays.fill(suf, n);
int p = n - 1, j = m - 1;
while (j >= 0) {
while (p >= 0 && s.charAt(p) != t.charAt(j)) p--;
if (p < 0) break;
suf[j] = p;
p--;
j--;
}
int first = j + 1;
if (first == 0) return 0;
int ans = first, q = 0, k = first;
for (int i = 0; i < m; i++) {
while (q < n && s.charAt(q) != t.charAt(i)) q++;
if (q == n) break;
q++;
if (k <= i) k = i + 1;
while (k < m && suf[k] < q) k++;
ans = Math.min(ans, k - i - 1);
}
return ans;
}C++
int minimumScore(string s, string t) {
int n = s.size(), m = t.size();
vector<int> suf(m + 1, n);
int p = n - 1, j = m - 1;
while (j >= 0) {
while (p >= 0 && s[p] != t[j]) p--;
if (p < 0) break;
suf[j] = p;
p--;
j--;
}
int first = j + 1;
if (first == 0) return 0;
int ans = first, q = 0, k = first;
for (int i = 0; i < m; i++) {
while (q < n && s[q] != t[i]) q++;
if (q == n) break;
q++;
if (k <= i) k = i + 1;
while (k < m && suf[k] < q) k++;
ans = min(ans, k - i - 1);
}
return ans;
}JavaScript
var minimumScore = function(s, t) {
var n = s.length, m = t.length;
var suf = new Array(m + 1).fill(n);
var p = n - 1, j = m - 1;
while (j >= 0) {
while (p >= 0 && s[p] !== t[j]) p--;
if (p < 0) break;
suf[j] = p;
p--;
j--;
}
var first = j + 1;
if (first === 0) return 0;
var ans = first, q = 0, k = first;
for (var i = 0; i < m; i++) {
while (q < n && s[q] !== t[i]) q++;
if (q === n) break;
q++;
if (k <= i) k = i + 1;
while (k < m && suf[k] < q) k++;
ans = Math.min(ans, k - i - 1);
}
return ans;
};Also on the editorial tab: C, C#, Go, Kotlin, PHP, Ruby, Rust, Swift, TypeScript.
All 515 strings problems · the whole catalogue
Learn the technique: Strings · Binary Search