Is there a way to make my function run faster?
Question:
I have this function, which task is to find out how many numbers, can be selected from the list in such a way, that the difference between any two selected numbers is not greater than t. How can I make it so that its time complexity is O(nlogn)?
def find_numbers(num_list, t):
sorted_list=sorted(num_list)
counter=0
k=0
n=0
for i in range(len(sorted_list)):
for j in range(k, len(sorted_list)):
if sorted_list[j]-sorted_list[k]<=t:
counter+=1
else:
break
k+=1
if counter>n:
n=counter
counter=0
return n
Some examples of how it should work
print(find_numbers([2, 7, 14, 11, 7, 15], 11)) # 5
print(find_numbers([4, 2, 7, 1], 0)) # 1
print(find_numbers([7, 3, 1, 5, 2], 2)) # 3
In the third example, three numbers can be selected from the list [7,3,1,5,2]: 3, 1 and 2, and the differences between these numbers are all at most 2.
Answers:
You can do with zip
def find_numbers(num_list, t):
return return len([i for i in zip(num_list, num_list[1:]) if i[0]-i[1] <= t])
Executions:
In [1]: print(find_numbers([2, 7, 14, 11, 7, 15], 11))
5
In [2]: print(find_numbers([4, 2, 7, 1], 0))
1
In [3]: print(find_numbers([7, 3, 1, 5, 2], 2))
2
Your general design, of sorting the list, then scanning through to see what the longest run of numbers separated by no more than t
it is sound.
However, you can be more efficient with your scan if you realize you don’t need to reset j
each time you increase i
. All numbers up to sorted_list[j]
that were within t
of sorted_list[i]
will also be within that range of sorted_list[i+1]
, since the latter is larger. This means the scan can be O(n)
rather than O(n**2)
:
def find_numbers(num_list, t):
sorted_list=sorted(num_list)
n = 0
j = 1 # j points to the first index that might be larger by more than t
for i in range(len(sorted_list)):
while j < len(sorted_list) and sorted_list[j] - sorted_list[i] < t:
j += 1
if j - i > n: # no need to manually count, the indexes can do that for us
n = j - i
return n
There might be a slightly more elegant way to code this, but this version solves the complexity issue you were asking about.
I have this function, which task is to find out how many numbers, can be selected from the list in such a way, that the difference between any two selected numbers is not greater than t. How can I make it so that its time complexity is O(nlogn)?
def find_numbers(num_list, t):
sorted_list=sorted(num_list)
counter=0
k=0
n=0
for i in range(len(sorted_list)):
for j in range(k, len(sorted_list)):
if sorted_list[j]-sorted_list[k]<=t:
counter+=1
else:
break
k+=1
if counter>n:
n=counter
counter=0
return n
Some examples of how it should work
print(find_numbers([2, 7, 14, 11, 7, 15], 11)) # 5
print(find_numbers([4, 2, 7, 1], 0)) # 1
print(find_numbers([7, 3, 1, 5, 2], 2)) # 3
In the third example, three numbers can be selected from the list [7,3,1,5,2]: 3, 1 and 2, and the differences between these numbers are all at most 2.
You can do with zip
def find_numbers(num_list, t):
return return len([i for i in zip(num_list, num_list[1:]) if i[0]-i[1] <= t])
Executions:
In [1]: print(find_numbers([2, 7, 14, 11, 7, 15], 11))
5
In [2]: print(find_numbers([4, 2, 7, 1], 0))
1
In [3]: print(find_numbers([7, 3, 1, 5, 2], 2))
2
Your general design, of sorting the list, then scanning through to see what the longest run of numbers separated by no more than t
it is sound.
However, you can be more efficient with your scan if you realize you don’t need to reset j
each time you increase i
. All numbers up to sorted_list[j]
that were within t
of sorted_list[i]
will also be within that range of sorted_list[i+1]
, since the latter is larger. This means the scan can be O(n)
rather than O(n**2)
:
def find_numbers(num_list, t):
sorted_list=sorted(num_list)
n = 0
j = 1 # j points to the first index that might be larger by more than t
for i in range(len(sorted_list)):
while j < len(sorted_list) and sorted_list[j] - sorted_list[i] < t:
j += 1
if j - i > n: # no need to manually count, the indexes can do that for us
n = j - i
return n
There might be a slightly more elegant way to code this, but this version solves the complexity issue you were asking about.