Reputation: 443
So this is an algorithms question I was working out on HackerRank. It passes all the test cases except one because it times out.
I tried making a couple of improvements but it still keeps timing out. I want to understand how you can look at your own code and find places where it is slow.
Please note that I am not looking at alternative logics to solve the problem. This is the solution that came to my mind and I want to try and quicken it.
The question is as follows:
Problem Statement
Given a list of N integers, your task is to select K integers from the list such that its unfairness is minimized.
If (x1,x2,x3,…,xk) are K numbers selected from the list N, the unfairness is defined as
max(x1,x2,…,xk)−min(x1,x2,…,xk) where max denotes the largest integer among the elements of K, and min denotes the smallest integer among the elements of K.
Input Format
The first line contains an integer N. The second line contains an integer K. N lines follow. Each line contains an integer that belongs to the list N.
Link to the problem: https://www.hackerrank.com/challenges/angry-children/copy-from/11910253
First attempt:
n, k = int(input()), int(input())
num = sorted([ int(input()) for i in range(0,n) ])
lower, min_unfairness, upper = 0, 0, k
while upper <= len(num):
current = num[lower:upper]
unfairness = current[-1] - current[0]
if lower == 0:
min_unfairness = unfairness
else:
if unfairness < min_unfairness:
min_unfairness = unfairness
if min_unfairness == 0:
break
lower += 1
upper += 1
print (min_unfairness)
Second Attempt: Improved further by removing the check for lower == 0 from the loop since that happens only in the first iteration.
n, k = int(input()), int(input())
num = sorted([ int(input()) for i in range(0,n) ])
lower, min_unfairness, upper = 0, 0, k
#Finding the unfairness of the 1st set and assigning it as min
current = num[lower:upper]
unfairness = current[-1] - current[0]
min_unfairness = unfairness
lower += 1
upper += 1
while upper <= len(num) and min_unfairness != 0:
#Finding unfairness of current set
current = num[lower:upper]
unfairness = current[-1] - current[0]
#Set it as min if it is lower than current minimum
if unfairness < min_unfairness:
min_unfairness = unfairness
lower += 1
upper += 1
print (min_unfairness)
I am not sure what approach I should take whilte trying to analyse this problem. Any suggestions are welcome.
Upvotes: 4
Views: 249
Reputation: 443
With Kolmar and Steven's help, I wrote the following piece:
n, k = int(input()), int(input())
num = sorted([ int(input()) for i in range(0,n) ])
min_unfairness = min( max_value - min_value for min_value, max_value in zip(num, num[k-1:]) )
print(min_unfairness)
Posting it as an answer here, so that if anyone wants to have a quick look at the answer, they can see this :)
Upvotes: 2
Reputation: 14224
The slowest thing you do is copying a part of the list: current = num[lower:upper]
. This brings the complexity of this step up from O(n) to O(n•k).
What you really should do is just take the elements, which define the unfairness of this sublist directly by their indexes:
min_unfairness = min(num[i+k-1] - num[i] for i in range(n-k+1))
Clarification: When the index of the first element of some selection is i
, the largest element has index i+k-1
, so the unfairness of this selection is equal to num[i+k-1] - num[i]
. The code (num[i+k-1] - num[i] for i in range(n-k+1))
gives the iterator over unfairnesses of the relevant selections. So min(num[i+k-1] - num[i] for i in range(n-k+1))
finds the smallest unfairness in this iterator.
Upvotes: 2