Reputation: 2316
I have this code that finds the smallest difference between the indices of equal values in a list. (It finds the smallest "distance" between equal values.) I want to optimize its time complexity. My code currently runs in O(N^2).
def func(arr):
length = len(arr)
res = 0
for i and j in range(length):
if arr[i] == arr[j]:
res = min(res,i-j)
return res
How can I optimize it?
Upvotes: 0
Views: 72
Reputation: 17263
Here's a simple solution that has O(n) time complexity. For every item in the array it will store the first index it's found from and then later retrieves it to calculate the difference:
def func(arr):
d = {}
return max(i - d.setdefault(x, i) for i, x in enumerate(arr))
Update: If the items on the list are not hashable or sortable then you need to compare them all against each other and that can be only done in O(n^2) time. You could improve the original code by starting the inner loop from i+1
which would also get rid of abs
. Another improvement would be to call max
only once instead of after every match:
def func(arr):
gen = (j - i for i in range(len(arr) - 1) for j in range(i + 1, len(arr))
if arr[i] == arr[j])
return max(gen, default=0)
Note that above only works on Python 3.x because max
on 2.x doesn't support default
parameter.
Update: The most efficient algorithm I could come up with to cover the scenario of unhashable/sortable items is to compare all pairs with difference of len(arr) - 1
and if you don't find a match then compare pairs of len(arr) - 2
and so forth. This is of course still O(n^2) in case that all items on the list are unique:
def func(arr):
for i in range(len(arr) - 1, 0, -1):
for j in range(len(arr) - i):
if arr[j] == arr[j+i]:
return i
return 0
Upvotes: 6
Reputation: 1469
You can get a bit of a speed up by bringing that max() out to the top and using list comprehensions (although you'll still need to tackle the O notation complexity):
def func(arr):
return max([abs(i - j)
for i in range(len(arr))
for j in range(len(arr))
if arr[i] == arr[j]])
Upvotes: 0