🧠
Two Pointers from End (Simulate Backspaces On The Fly)
💡 This approach improves space by simulating the backspace effect while traversing from the end, avoiding extra stacks.
Intuition
Start from the end of both strings and move backwards, skipping characters that should be deleted due to backspaces, then compare characters one by one.
Algorithm
- Initialize two pointers at the end of S and T.
- For each pointer, skip characters that are deleted by backspaces using a skip counter.
- Compare the current characters after skipping; if different, return false.
- Move both pointers backward and repeat until both strings are fully traversed.
💡 The tricky part is correctly skipping characters affected by backspaces before comparing.
def backspaceCompare(S: str, T: str) -> bool:
i, j = len(S) - 1, len(T) - 1
skipS = skipT = 0
while i >= 0 or j >= 0:
while i >= 0:
if S[i] == '#':
skipS += 1
i -= 1
elif skipS > 0:
skipS -= 1
i -= 1
else:
break
while j >= 0:
if T[j] == '#':
skipT += 1
j -= 1
elif skipT > 0:
skipT -= 1
j -= 1
else:
break
if i >= 0 and j >= 0 and S[i] != T[j]:
return False
if (i >= 0) != (j >= 0):
return False
i -= 1
j -= 1
return True
# Driver code
if __name__ == '__main__':
print(backspaceCompare("ab#c", "ad#c")) # True
print(backspaceCompare("ab##", "c#d#")) # True
print(backspaceCompare("a#c", "b")) # False
Line Notes
i, j = len(S) - 1, len(T) - 1Start pointers at the end of each string
skipS = skipT = 0Counters to track how many chars to skip due to backspaces
while i >= 0:Skip characters in S affected by backspaces
if S[i] == '#':Increment skip counter when backspace found
elif skipS > 0:Skip a character if skip counter positive
if i >= 0 and j >= 0 and S[i] != T[j]:Compare current characters after skipping
if (i >= 0) != (j >= 0):If one string ended before the other, return false
i -= 1; j -= 1Move both pointers backward
public class Solution {
public static boolean backspaceCompare(String S, String T) {
int i = S.length() - 1, j = T.length() - 1;
int skipS = 0, skipT = 0;
while (i >= 0 || j >= 0) {
while (i >= 0) {
if (S.charAt(i) == '#') {
skipS++;
i--;
} else if (skipS > 0) {
skipS--;
i--;
} else {
break;
}
}
while (j >= 0) {
if (T.charAt(j) == '#') {
skipT++;
j--;
} else if (skipT > 0) {
skipT--;
j--;
} else {
break;
}
}
if (i >= 0 && j >= 0 && S.charAt(i) != T.charAt(j)) return false;
if ((i >= 0) != (j >= 0)) return false;
i--;
j--;
}
return true;
}
public static void main(String[] args) {
System.out.println(backspaceCompare("ab#c", "ad#c")); // true
System.out.println(backspaceCompare("ab##", "c#d#")); // true
System.out.println(backspaceCompare("a#c", "b")); // false
}
}
Line Notes
int i = S.length() - 1, j = T.length() - 1;Initialize pointers at end of strings
int skipS = 0, skipT = 0;Skip counters for backspaces
while (i >= 0)Skip characters in S affected by backspaces
if (S.charAt(i) == '#')Increment skip counter on backspace
else if (skipS > 0)Skip character if skip counter positive
if (i >= 0 && j >= 0 && S.charAt(i) != T.charAt(j))Compare current characters
if ((i >= 0) != (j >= 0))Check if one string ended before the other
i--; j--;Move pointers backward
#include <iostream>
#include <string>
using namespace std;
bool backspaceCompare(string S, string T) {
int i = (int)S.size() - 1, j = (int)T.size() - 1;
int skipS = 0, skipT = 0;
while (i >= 0 || j >= 0) {
while (i >= 0) {
if (S[i] == '#') {
skipS++;
i--;
} else if (skipS > 0) {
skipS--;
i--;
} else {
break;
}
}
while (j >= 0) {
if (T[j] == '#') {
skipT++;
j--;
} else if (skipT > 0) {
skipT--;
j--;
} else {
break;
}
}
if (i >= 0 && j >= 0 && S[i] != T[j]) return false;
if ((i >= 0) != (j >= 0)) return false;
i--;
j--;
}
return true;
}
int main() {
cout << boolalpha;
cout << backspaceCompare("ab#c", "ad#c") << '\n'; // true
cout << backspaceCompare("ab##", "c#d#") << '\n'; // true
cout << backspaceCompare("a#c", "b") << '\n'; // false
return 0;
}
Line Notes
int i = (int)S.size() - 1, j = (int)T.size() - 1;Pointers start at end of strings
int skipS = 0, skipT = 0;Skip counters for backspaces
while (i >= 0)Skip characters in S affected by backspaces
if (S[i] == '#')Increment skip counter on backspace
else if (skipS > 0)Skip character if skip counter positive
if (i >= 0 && j >= 0 && S[i] != T[j])Compare current characters
if ((i >= 0) != (j >= 0))Check if one string ended before the other
i--; j--;Move pointers backward
function backspaceCompare(S, T) {
let i = S.length - 1, j = T.length - 1;
let skipS = 0, skipT = 0;
while (i >= 0 || j >= 0) {
while (i >= 0) {
if (S[i] === '#') {
skipS++;
i--;
} else if (skipS > 0) {
skipS--;
i--;
} else {
break;
}
}
while (j >= 0) {
if (T[j] === '#') {
skipT++;
j--;
} else if (skipT > 0) {
skipT--;
j--;
} else {
break;
}
}
if (i >= 0 && j >= 0 && S[i] !== T[j]) return false;
if ((i >= 0) !== (j >= 0)) return false;
i--;
j--;
}
return true;
}
// Test cases
console.log(backspaceCompare("ab#c", "ad#c")); // true
console.log(backspaceCompare("ab##", "c#d#")); // true
console.log(backspaceCompare("a#c", "b")); // false
Line Notes
let i = S.length - 1, j = T.length - 1;Initialize pointers at end
let skipS = 0, skipT = 0;Skip counters for backspaces
while (i >= 0)Skip characters in S affected by backspaces
if (S[i] === '#')Increment skip counter on backspace
else if (skipS > 0)Skip character if skip counter positive
if (i >= 0 && j >= 0 && S[i] !== T[j])Compare current characters
if ((i >= 0) !== (j >= 0))Check if one string ended before the other
i--; j--;Move pointers backward
Each character is processed at most once from the end, and no extra space proportional to input size is used.
💡 For strings of length 100,000, this means about 200,000 operations but constant extra memory.
Interview Verdict: Accepted
This is the preferred approach in interviews due to its optimal space usage and clear logic.