Let's define the functions again:
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
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
Mostly for fun, let's make a function that returns a random string of "a"s and "b"s of a specified length.
import random
def get_seq_ab(length):
s = ""
for i in range(length):
if random.random() > .5:
s += "a"
else:
s += "b"
return s
Here's an example:
s = get_seq_ab(100)
s
We can now apply either of the version of longest_run:
longest_run1(s, "a")
longest_run2(s, "a")
Let's now write a function to time how long a function like longest_run() takes:
import time
def timeit(func, arg1, arg2):
'''Return the estimate of the runtime, in seconds, of func(arg1, arg2),
by running the command several times and averaging the results'''
N = 50
t0 = time.time()
for i in range(N):
func(arg1, arg2)
t1 = time.time()
return (t1-t0)/N
We'd like to try evaluating the runtimes of the following lengths of the string (note that those are not strictly speaking the worst-case runtimes, but they're pretty close, since the maximum runs are of length about 10, usually. If we wanted to be very rigorous about this, we'd just try to run the functions on length*"b", "a". (Of course, we'd have to be able to figure out that that is the worst case.)
lengths = list(range(300, 1800, 300))
lengths
times1 = []
times2 = []
for length in lengths:
s = get_seq_ab(length)
times1.append(timeit(longest_run1, s, "a"))
times2.append(timeit(longest_run2, s, "a"))
times1
times2
Let's plot those results (instructions for making sure you can import matplotlib.pyplot are on the course website.)
import matplotlib.pyplot as plt
plt.figure(1)
plt.plot(lengths, times1)
plt.xlabel("len(s)")
plt.ylabel("runtime (sec)")
plt.title("The $O(n)$ algorithm")
plt.figure(2)
plt.plot(lengths, times2)
plt.xlabel("len(s)")
plt.ylabel("runtime (sec)")
plt.title("The $O(n^2)$ algorithm")
We could try to plot both curves on the same Figure, but it won't look good, because the scales are so different:
plt.figure(3)
plt.plot(lengths, times1)
plt.plot(lengths, times2)
plt.xlabel("len(s)")
plt.ylabel("runtime (sec)")
plt.title("The $O(n)$ algorithm and the $O(n^2)$ algorithm")
We'd have to plot the lines on a log-scale to make things make more sense:
plt.figure(4)
plt.plot(lengths, times1)
plt.plot(lengths, times2)
plt.xlabel("len(s)")
plt.ylabel("runtime (sec)")
plt.yscale("log")
plt.title("The $O(n)$ algorithm and $O(n^2)$ algorithm")