I observe that Alice can make a move iff the string contains at least one vowel, because she can always remove a single-letter substring that is a vowel (which has 1—odd—vowel). If there are no vowels, Alice has no valid first move and immediately loses. If there is at least one vowel, Alice can win: she can either delete the whole string if the total number of vowels is odd, or delete a suitable odd-vowel substring (e.g., any single vowel) to force a position where Bob has no winning reply. Therefore, the outcome reduces to a simple check—Alice wins iff the string contains any vowel.
class Solution:
def doesAliceWin(self, s: str) -> bool: