I was given a task where given a string of '0's and '1's, return the longest substring where the count of '0's and '1's are equal. I was told also that the code should be O(n) and space O(1).
Below is what I came up with:
def max_equal_sub(s):
'''
I get the substrings by iterating over the starts and the ends for each start. For each
of these, check if the counts are equal.
'''
return max((s[b:e] for b in range(len(s)) for e in range(b, len(s)) if s[b:e].count('1') == s[b:e].count('0')), key=len)
def main():
TESTS = ('000', '1111', '001010101', '0001010101', '01010101', '000000111010101',
'0000001110101011', '00000011101010111111111111111')
for binstr in TESTS:
print(max_equal_sub(binstr))
if __name__ == '__main__':
main()
This code is all working fine, but I was told that this runs at O(n2), not O(n).
Following that I have some questions:
- What makes it O(n2), and how can I make it so that it is O(n).
- I was told that it needed to be 'space O(1)'. Does it run at that? What would make it run at space O(1) and why?
- In the function
max_equal_sub, would it be more efficient to putlen(s)into a variable to avoid calling it again and again? - In the function
max_equal_sub, I dos[b:e]three times. Surely there is a more efficient way?
(Optional, but favoured):
- Are there any other things I could do to make it faster?
- You could make it PEP8-compliant along the way if you wish.
- Any other recommendations, perhaps regarding program logic.