Finding Substrings with At Most One Different Character in JavaScript
Finding substrings within a string is a common task in programming. However, sometimes you might need to find substrings that adhere to specific conditions, like having at most one character different from a given pattern. Let's delve into how to accomplish this using JavaScript.
The Problem
Imagine you have a string like "banana" and you want to find all substrings that are similar to "bana" but allow for one character to be different. In this case, "bana", "banna", and "banana" would all be valid substrings. This problem requires us to iterate through the string and check each substring for the specified condition.
Original Code Example
function findSubstrings(str, pattern) {
const result = [];
for (let i = 0; i < str.length; i++) {
for (let j = i + 1; j <= str.length; j++) {
let substring = str.substring(i, j);
if (checkSubstring(substring, pattern)) {
result.push(substring);
}
}
}
return result;
}
function checkSubstring(substring, pattern) {
let diffCount = 0;
for (let i = 0; i < Math.min(substring.length, pattern.length); i++) {
if (substring[i] !== pattern[i]) {
diffCount++;
if (diffCount > 1) {
return false;
}
}
}
return true;
}
let str = "banana";
let pattern = "bana";
let substrings = findSubstrings(str, pattern);
console.log(substrings); // Output: ["bana", "banna", "banana"]
This code snippet defines two functions:
findSubstrings
: This function iterates through the string and checks each possible substring against the pattern using thecheckSubstring
function.checkSubstring
: This function compares the substring to the pattern character by character and counts the number of differing characters. If the difference count exceeds one, it returnsfalse
, indicating the substring doesn't meet the condition.
Analysis and Optimization
While the above code functions correctly, it's inefficient for longer strings. The nested loops create a time complexity of O(n^2), which can become a performance bottleneck. We can improve the algorithm using a sliding window approach.
Sliding Window Approach
The sliding window technique iterates through the string using two pointers:
- start: The beginning of the current window.
- end: The end of the current window.
We maintain a diffCount
variable to track the number of different characters within the window. As we slide the window, we adjust the diffCount
based on the current character. If diffCount
exceeds 1, we shift the start
pointer forward to shrink the window until the condition is met again.
function findSubstringsWithWindow(str, pattern) {
const result = [];
let start = 0;
let end = 0;
let diffCount = 0;
while (end < str.length) {
if (str[end] !== pattern[end - start]) {
diffCount++;
}
while (diffCount > 1) {
if (str[start] !== pattern[start - start]) {
diffCount--;
}
start++;
}
if (end - start + 1 === pattern.length) {
result.push(str.substring(start, end + 1));
}
end++;
}
return result;
}
let str = "banana";
let pattern = "bana";
let substrings = findSubstringsWithWindow(str, pattern);
console.log(substrings); // Output: ["bana", "banna", "banana"]
This approach significantly improves the time complexity to O(n), making it suitable for handling larger strings.
Conclusion
Finding substrings with specific conditions can be a challenging task, but with the right approach, it becomes manageable. The sliding window technique offers a more efficient solution compared to nested loop approaches, improving the overall performance of your code. Remember to carefully analyze the problem and choose the most appropriate algorithm for the task.