Here is the longest_run() function that we wrote a little while ago:
def longest_run1(s, c):
run = 0
max_run = 0
if c == "z":
s += "y"
else:
s += "z"
for ch in s:
if ch != c:
max_run = max(run, max_run)
run = 0
else:
run += 1
return max_run
The worst-case runtime complexity analysis for this function is pretty easy: we just have one loop, and each iteration of that loop takes a constant amount of time. The loop runs for n = len(s) times. The runtime is always the same for a given len(s), so there is no concern about worst-case runtime here.
The function will take an amount of time that's proportional to len(s). In other words, the worst-case runtime complexity of the function is $\mathcal{O}(n)$ for n = len(s).
Here is another version of longest_run. This time, the strategy is to, in sequence:
Try to find a run of length len(s), and return len(s) if the run is found.
Try to find a run of length len(s)-1, and return len(s)-1 if the run is found.
Try to find a run of length len(s)-2, and return len(s)-2 if the run is found.
And so on.
Because we start bu looking for a run of the maximal length (rather than length 0), this works. A short version of the code that's hard to analyze is:
def longest_run2(s, ch):
for longest in range(len(s), -1, -1):
if ch*longest in s:
return longest
return 0 #Optional, 0 will be returned anyway since '' is in any string
Here is an easier-to-analyze version:
def longest_run2(s, ch):
for longest in range(len(s), -1, -1):
cur_run = 0
for i in range(len(s)):
if s[i] == ch:
cur_run += 1
else:
cur_run = 0
if cur_run == longest:
return longest
return 0
It's not true that each iteration of the outer loop runs for a constant amount of time -- the time it takes to run one iteration of the outer loop depends on len(s). Here, we also have different cases -- in the best case, we return almost right away; in the worst case, we don't return until we reach return 0.
An iteration of the inner loop does take a constant amount of time. In the worst case, for every iteration of the outer loop, the inner loop runs len(s) times. The outer loop also runs len(s) times. That means that the block of code starting from if s[i] == ch will run for a total of len(s)*len(s) = len(s)^2 times.
That means that the worst-case runtime complexity of the function is $\mathcal{O}(n^2)$, where n = len(s).