A "bad" pair consists of the same letter in different cases adjacent to each other (like "aA" or "Aa"). We repeatedly scan the string looking for such pairs. When we find one, we remove both characters and restart the scan since removing a pair might create a new bad pair from previously non-adjacent characters.
0 and scan through the string.i, check if the current character and the previous character form a bad pair (same letter, different cases).i by 2 to recheck, and update the string length.A stack naturally handles the "undo" pattern we need. As we process each character, we compare it with the top of the stack. If they form a bad pair (same letter, different cases), we pop the stack, effectively removing both characters. Otherwise, we push the current character. This handles cascading removals automatically.
class Solution:
def makeGood(self, s: str) -> str:
def lower(c):
if ord(c) < ord('a'):
return chr(ord('a') + ord(c) - ord('A'))
return c
stack = []
i = 0
while i < len(s):
if stack and stack[-1] != s[i] and lower(stack[-1]) == lower(s[i]):
stack.pop()
else:
stack.append(s[i])
i += 1
return "".join(stack)We can simplify the bad pair check using ASCII values. In ASCII, the difference between a lowercase letter and its uppercase counterpart is exactly 32 (e.g., 'a' is 97 and 'A' is 65). So if the absolute difference between two characters is 32, they are the same letter in different cases.
32, pop the stack.Instead of using extra space for a stack, we can simulate it in-place using two pointers. The left pointer l represents the "top" of our virtual stack, while the right pointer r scans through the input. Characters before position l form our result. When we find a bad pair, we "pop" by decrementing l.
l = 0.r from 0 to the end:l > 0 and the character at r forms a bad pair with the character at l - 1 (ASCII difference of 32), decrement l to "pop" the pair.r to position l and increment l.0 to l.