Highly likely this is from LeetCode, so I benchmarked our solutions there. Two attemptsTimes from three submissions:
77.7 76.28 78.7 ms Jan_B
13.0 12.5 12.8 ms MatBailie
11.9 ms 11.7 Simon_Brahan
2111.7 ms no_comment_minimal_fix_1Simon_Brahan
1622.0 ms2 no_comment_minimal_fix_2
21.7 522.01 ms no_comment_regex
no_comment_minimal_fix_1
7615.59 ms 15.6 Jan_B
1216.51 ms MatBailieno_comment_minimal_fix_2
11 2.67 ms Simon_Brahan
2.7 21 2.7 ms no_comment_minimal_fix_1no_comment_numpy
15 5.94 ms no_comment_minimal_fix_2
5.3 4 5.83 ms no_comment_regex
My NumPy solution inspired by Eman Yalpsid's answer takes advantage of the input strings guaranteed to be ASCII.
import numpy as np
class Solution:
def reverseVowels(self, s: str, timess=[]) -> str:
from time import perf_counter as time
funcs = [
self.no_comment_minimal_fix_1,
self.no_comment_minimal_fix_2,
self.no_comment_regex,
self.no_comment_numpy,
self.Jan_B,
self.MatBailie,
self.Simon_Brahan,
]
names = sorted(f.__name__ for f in funcs)
# Measure each solution on this test case
times = {f: [] for f in names}
n = 1
for _ in range(10):
shuffle(funcs)
for f in funcs:
t = time()
for _ in range(n):
f(s)
times[f.__name__].append(time() - t)
timess.append(times)
# Check correctness
result = funcs[0](s)
for f in funcs:
if f(s) != result:
return None
# After all test cases, show stats
if len(timess) == 480:
for f in names:
print(f'{sum(min(times[f]) for times in timess) / n * 1e3:5.1f} ms ', f)
return 'intentionally wrong answer so we get to see the output'
return result
def no_comment_minimal_fix_1(self, s: str) -> str:
v = []
vowels = ['a', 'e', 'i', 'o', 'u']
for c in s:
if c.lower() in vowels:
v.append(c)
v.reverse()
s = list(s)
j = 0
for i in range(len(s)):
if s[i].lower() in vowels:
s[i] = v[j]
j += 1
s = "".join(s)
return s
def no_comment_minimal_fix_2(self, s: str) -> str:
v = []
vowels = ['a', 'e', 'i', 'o', 'u']
for c in s:
if c.lower() in vowels:
v.append(c)
v.reverse()
V = set(v)
s = list(s)
j = 0
for i in range(len(s)):
if s[i] in V:
s[i] = v[j]
j += 1
s = "".join(s)
return s
def MatBailie(self, s: str) -> str:
vowels = [
(c, ix)
for ix, c in enumerate(s)
if c.lower() in {'a', 'e', 'i', 'o', 'u'}
]
s = list(s)
half = len(vowels) // 2
vowel_pairs = zip(
vowels[:half],
vowels[-half:][::-1]
)
for a, b in vowel_pairs:
s[a[1]] = b[0]
s[b[1]] = a[0]
return "".join(s)
def Simon_Brahan(self, s: str) -> str:
vowels = set(['a', 'e', 'i', 'o', 'u'])
s_chars = list(s)
vowels_in_s = []
vowel_indexes_in_s = []
for idx, char in enumerate(s_chars):
if char.lower() in vowels:
vowels_in_s.append(char)
vowel_indexes_in_s.append(idx)
vowel_indexes_in_s.reverse()
for idx, char in zip(vowel_indexes_in_s, vowels_in_s):
s_chars[idx] = char
return ''.join(s_chars)
def no_comment_regex(self, s: str) -> str:
a = re.split('([aeiouAEIOU])', s)
a[1::2] = a[-2::-2]
return ''.join(a)
def no_comment_numpy(self, s: str) -> str:
b = bytearray(s, 'ascii')
a = np.frombuffer(b, dtype=np.uint8)
mask = self.vowel[a]
a[mask] = a[mask][::-1]
return b.decode('ascii')
vowel = np.array([chr(i) in 'aeiouAEIOU' for i in range(128)])
def Jan_B(self, s: str) -> str:
# set instead of list with both lower and upper case to omit .lower()
vowels = {'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'}
# list comprehension instead of loop
v = [c for c in s if c in vowels]
# reverse function instead of slicing
v.reverse()
# adding to string instead of converting to and from list
result = ''
# looping directly over the string
for char in s:
if char in vowels:
char = v.pop(0)
result += char
return result
Summarizer script (with fewer results):
from collections import defaultdict
results = '''
77.7 ms Jan_B
13.0 ms MatBailie
76.8 ms Jan_B
12.5 ms MatBailie
78.7 ms Jan_B
12.8 ms MatBailie
'''
times = defaultdict(list)
for line in results.splitlines():
if line:
times[line[10:]].append(line[:5])
for name, ts in times.items():
print(*ts, 'ms ', name)
Attempt This Online!