Shortest Path Cost Engine 2 — Problem Statement & Solution Guide
Problem Description
Shortest Path Cost Engine 2
You are given a source string S and a list of Q query strings. For each query string T you must determine whether T can be obtained from S by deleting zero or more characters without reordering the remaining characters. In other words, T is a subsequence of S if all characters of T appear in S in the same relative order. For each query output "YES" if T is a subsequence of S, otherwise output "NO".
Input format:
- The first line contains the string S.
- The second line contains an integer Q, the number of queries.
- Each of the following Q lines contains a query string T.
Output format:
- For each query, output a single line containing either "YES" or "NO".
The task is to answer all queries efficiently, taking into account the potentially large size of S and the total length of all queries.
DSA Pattern Breakdown
DSA Pattern Breakdown
"Shortest Path Cost Engine 2"
WHY DOES IT MATTER?
The subsequence check is a fundamental pattern in string processing, often appearing as a subproblem in more complex tasks like edit distance, pattern matching, and text compression. Mastering the two-pointer technique for subsequences builds intuition for greedy algorithms and efficient linear scans, which are critical for handling large-scale data in real-time systems.
OPTIMIZATION CHALLENGE
The key insight is that we do not need to check all possible alignments of T in S. Instead, we can greedily match characters in T with the earliest possible occurrences in S. This reduces the problem from a combinatorial search to a linear scan, leveraging the fact that the relative order is the only constraint.
REAL-WORLD CONNECTION
This pattern is used in version control systems (e.g., Git) to check if a commit history is a subsequence of another, in log analysis to verify if a sequence of events occurred in order, and in spell-checkers to determine if a user's input is a subsequence of a known word, allowing for typo correction.
In interviews, always clarify the constraints: Is S static? Are there multiple queries? If so, suggest the precomputation approach. If not, the two-pointer method is sufficient. Mentioning the trade-off between precomputation cost and query time demonstrates system design thinking.
COMPLEXITY AT A GLANCE
O(N + M) per query, or O(N * 26 + Q * M) with precomputation for Q queriesO(1) per query, or O(N * 26) with precomputationCore Theory — Why This Approach?
The problem of determining if string T is a subsequence of string S is a classic application of the two-pointer technique. The core intuition relies on the fact that the relative order of characters in T must be preserved in S. We can traverse S once while maintaining a pointer to the current character we are looking for in T. If a match is found, we advance the pointer in T; otherwise, we simply continue scanning S. This greedy approach is optimal because skipping a potential match in S never helps us find a valid subsequence later, as the order is fixed. The time complexity is O(N + M) where N is the length of S and M is the length of T, which is linear and highly efficient for large inputs.
Naive approaches, such as generating all subsequences of S or using dynamic programming with a 2D table, are computationally expensive. Generating all subsequences takes O(2^N) time, which is infeasible for large N. Dynamic programming, while correct, uses O(N*M) time and space, which is unnecessary for this specific problem since we only need a boolean result and the greedy nature of the subsequence check allows for a linear scan. The two-pointer method exploits the monotonicity of the indices: once we match a character in T, we never need to look back at previous characters in S for subsequent matches in T.
For multiple queries Q against the same source string S, we can optimize further by precomputing the next occurrence of each character in S. This allows each query to be answered in O(M * log(N)) or even O(M) with binary search or direct indexing, depending on the alphabet size. This is particularly useful when Q is large and S is static. The precomputation step takes O(N * 26) time and space, which is a one-time cost. This approach is common in systems where a fixed dictionary or template is matched against many user inputs, such as spell-checking engines or pattern matching in log analysis.
Interview Questions on This Problem
Q1How would you modify your solution to handle multiple queries efficiently if the source string S is very large and the number of queries Q is also large?
Precompute a next occurrence table for S. For each position i in S and each character c, store the index of the next occurrence of c after i. Then, for each query T, traverse T and use the table to jump to the next valid position in S. This reduces each query to O(M) time after an O(N * 26) precomputation.
Q2What if the characters in S and T are not limited to lowercase English letters but can be any Unicode character? How does your solution change?
The two-pointer approach remains O(N + M) and is unaffected by the alphabet size. However, if using the precomputation method for multiple queries, the space complexity of the next occurrence table would increase to O(N * |Σ|), where |Σ| is the size of the Unicode character set. In such cases, using a map or hash table for next occurrences might be more memory-efficient, though with higher constant factors.
Q3Can you extend this problem to find the minimum number of insertions required to make T a subsequence of S?
This becomes a more complex problem related to the Longest Common Subsequence (LCS). The minimum insertions would be M - LCS(S, T). However, if the question is about insertions into T to make it a subsequence of S, it is equivalent to finding the length of the longest subsequence of T that is also a subsequence of S, which is the LCS. The answer would be M - LCS_length.
Examples
Input
abpcplea 2 apple monkey
Output
YES NO
Explanation: S = "abpcplea". 1. Query "apple": We can match a->a, p->b? no, but we can skip b and match p->p, l->c? skip c, l->l, e->e, final e->a? skip a. All characters of "apple" appear in order, so output YES. 2. Query "monkey": The first character 'm' does not appear in S, so it cannot be a subsequence. Output NO.
Input
xyz 4 x xy xyz xyzz
Output
YES YES YES NO
Explanation: S = "xyz". - "x" matches the first character. - "xy" matches the first two characters. - "xyz" matches all three. - "xyzz" requires two 'z's but S has only one, so NO.
Input
a 2 a aa
Output
YES NO
Explanation: S = "a". - "a" matches the single character. - "aa" would need two 'a's, which S does not provide, so NO.
Constraints
- 1 <= |S| <= 100000
- 1 <= Q <= 100000
- 1 <= |T| <= 100000
- Sum of |T| over all queries <= 1000000
- All strings consist of lowercase English letters
Optimal Approach & Strategy
Use two pointers to traverse S and T simultaneously. Advance the T pointer only when a match is found in S. This runs in O(N + M) time and O(1) space.
Brute Force Approach
Generate all possible subsequences of S and check if T is among them. This takes O(2^N) time, which is infeasible for large N.
Verified Code Solutions
function solution(nums) {
let sum = 0;
for (let num of nums) {
sum += num;
}
return sum;
}class Solution {
public:
int solution(vector<int>& nums) {
int sum = 0;
for (int num : nums) {
sum += num;
}
return sum;
}
};class Solution {
public int solution(int[] nums) {
int sum = 0;
for (int num : nums) {
sum += num;
}
return sum;
}
}def solution(nums):
sum = 0
for num in nums:
sum += num
return sumfunction solution(nums) {
let sum = 0;
for (let num of nums) {
sum += num;
}
return sum;
}Asked in Top Tech Interviews
Solve in Interative Editor
Ready to test your code? Open our built-in compiler, run custom test suites, and see detailed complexity analysis reports instantly.