Don't bother with ord
Python already provide syntactic sugar for comparing characters in codepoint order, so ord(char) <= ord(s[index + 1])
can be shortened to char <= s[index+1]
Don't bother with the index
You only use index
as a mean to look at the next character in s
, you can dispense with it if you do
substr = s[0]
for char in s[1:]:
if substr[-1] <= char:
substr += char
else:
# Do your things
Don't use a string as an accumulator
Making substr
a string is (probably) not the most efficient way to do it, as strings are immutable and you are constantly modifying it, better to make it a list of chars and join it only when needed
final_substr = []
substr = [s[0]]
for char in s[1:]:
if substr[-1] <= char:
substr.append(char)
else:
if len(substr) > len(final_substr):
final_substr = substr
substr = [char]
if len(substr) > len(final_substr):
final_substr = substr
final_substr = ''.join(final_substr)
Extra fanciness
in the code above, the string slicing s[1:]
copies s
, which might be an issue if you have to apply this procedure to a lot of very long strings. You can avoid that copy by using an iterator over s
, changing the lines above to
s_iter = iter(s)
final_substr = []
substr = [next(s_iter)]
for char in s_iter:
# Nothing changes after this line
Or you could be more pedestrian and iterate over range(len(s))
.
In the same vein, if you expect to have to deal with long substrings, you could transform everything to keep track of only the bounds of substr
final_bounds = [0, 1]
substr_bounds = [0, 1]
for i in range(1, len(s)):
if s[i-1] <= s[i]:
substr_bounds[1] += 1
else:
if final_bounds[1] - final_bounds[0] < substr_bounds[1] - substr_bounds[0]:
final_bounds = substr
substr_bounds = (i, i)
if final_bounds[1] - final_bounds[0] < substr_bounds[1] - substr_bounds[0]:
final_bounds = substr
final_substr = s[final_bounds[0]:final_bounds[1]]
This version should be the most efficient of all memory-wise. I do find it disgraceful, though.