Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Dynamic Programming: Is second string subsequence of first JavaScript
We are given two strings str1 and str2, we are required to write a function that checks if str1 is a subsequence of str2.
A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters.
For example, "ace" is a subsequence of "abcde" while "aec" is not because the relative order is not maintained.
Understanding Subsequences
In a subsequence, characters must appear in the same order as in the original string, but they don't need to be consecutive. Here are some examples:
// Valid subsequences of "abcde"
console.log("Valid subsequences:");
console.log("'ace' from 'abcde' - positions 0,2,4");
console.log("'bd' from 'abcde' - positions 1,3");
console.log("'e' from 'abcde' - position 4");
// Invalid subsequences
console.log("\nInvalid subsequences:");
console.log("'aec' from 'abcde' - wrong order (e comes before c)");
Valid subsequences: 'ace' from 'abcde' - positions 0,2,4 'bd' from 'abcde' - positions 1,3 'e' from 'abcde' - position 4 Invalid subsequences: 'aec' from 'abcde' - wrong order (e comes before c)
Two-Pointer Approach
We use two pointers to traverse both strings. We advance the first pointer only when characters match, but always advance the second pointer.
const str1 = 'ace';
const str2 = 'abcde';
const isSubsequence = (str1, str2) => {
let i = 0; // pointer for str1
let j = 0; // pointer for str2
while (i < str1.length && j < str2.length) {
if (str1[i] === str2[j]) {
i++; // move to next character in str1
}
j++; // always move to next character in str2
}
// If we've matched all characters of str1
return i === str1.length;
};
console.log(`Is "${str1}" a subsequence of "${str2}"?`, isSubsequence(str1, str2));
Is "ace" a subsequence of "abcde"? true
Step-by-Step Example
const isSubsequenceWithSteps = (str1, str2) => {
let i = 0, j = 0;
console.log(`Checking if "${str1}" is subsequence of "${str2}"`);
while (i < str1.length && j < str2.length) {
console.log(`Comparing str1[${i}]='${str1[i]}' with str2[${j}]='${str2[j]}'`);
if (str1[i] === str2[j]) {
console.log(`Match found! Moving both pointers`);
i++;
} else {
console.log(`No match, moving j pointer only`);
}
j++;
}
const result = i === str1.length;
console.log(`Result: ${result} (matched ${i}/${str1.length} characters)`);
return result;
};
isSubsequenceWithSteps('ace', 'abcde');
Checking if "ace" is subsequence of "abcde" Comparing str1[0]='a' with str2[0]='a' Match found! Moving both pointers Comparing str1[1]='c' with str2[1]='b' No match, moving j pointer only Comparing str1[1]='c' with str2[2]='c' Match found! Moving both pointers Comparing str1[2]='e' with str2[3]='d' No match, moving j pointer only Comparing str1[2]='e' with str2[4]='e' Match found! Moving both pointers Result: true (matched 3/3 characters)
Testing Multiple Cases
const testCases = [
['ace', 'abcde', true],
['aec', 'abcde', false],
['abc', 'aabbcc', true],
['axc', 'ahbgdc', false],
['', 'abc', true], // empty string is subsequence of any string
['abc', '', false] // non-empty cannot be subsequence of empty
];
testCases.forEach(([str1, str2, expected]) => {
const result = isSubsequence(str1, str2);
console.log(`"${str1}" ? "${str2}": ${result} ${result === expected ? '?' : '?'}`);
});
"ace" ? "abcde": true ? "aec" ? "abcde": false ? "abc" ? "aabbcc": true ? "axc" ? "ahbgdc": false ? "" ? "abc": true ? "abc" ? "": false ?
Time and Space Complexity
The algorithm has O(n + m) time complexity where n and m are the lengths of str1 and str2 respectively. Space complexity is O(1) as we only use two pointer variables.
Conclusion
The two-pointer approach efficiently determines if one string is a subsequence of another by maintaining character order. This technique is fundamental in dynamic programming and string manipulation problems.
