How can i optimize this python code to reduce time complexity - python

I'm Trying To Solve A Problem.
Given 2 arrays of integers, A and B, both of size n.
Suppose you have a list of integers, initially empty. Now, you traverse the 2 arrays simultaneously for every i from 1 to n, and perform the following operation:
You append Ai to the list.
If the list now contains at least Bi distinct elements, you will remove Bi distinct elements from the list. If the list has more than Bi distinct elements, you will remove Bi distinct elements ordered by the frequency in the list, from highest frequency to lowest i.e. element with a higher frequency is removed first.
If 2 elements have the same frequency in the list, then you will remove the element with the lower value of Ai.
If you can perform this removal operation, then it is counted as a successful operation, else it is unsuccessful.
Note that in case of a successful operation, the updated list, from which Bi distinct elements have been removed, is taken for the next operation.
Example
Assumptions
n = 4
A = [1, 1, 2, 3]
B = [3, 2, 3, 2]
Approach
Initially, the list is empty.
For i = 1, you first append A1 to the list. So, the list becomes [1]. Now, B1 = 3, that is, you need at least 3 distinct elements in the list. So, the operation is unsuccessful.
For i = 2, you first append A2 to the list. So, the list becomes [1, 1]. Now, B2=2, that is, you need at least 2 distinct elements in the list, but the list has only 1 distinct element. So, the operation is unsuccessful.
For i = 3, you first append A3 to the list. So, list becomes [1, 1, 2]. Now, B3 = 3, that is, you need to remove at least 3 distinct elements in the list, but the list has 2 distinct elements. So, the operation is unsuccessful.
For i = 4, you first append A4 to the list. So, the list becomes [1, 1, 2, 3]. Now, B4 = 2, that is, you need to remove at least 2 distinct elements from the list, and the list has 3 distinct elements. So, the operation is successful. You remove a 1 as it has the highest frequency in the list, and then we remove 2 as it has a lower value than 3. So, the updated list is [1, 3].
Hence, the answer, which is the number of successful operations, is 1.
The Below Is My Code Its Working fine for small cases. But FOr higher cases it giving time limit exceeded.
T = int(input())# No of test cases
for _ in range(T):
N = int(input()) # Numbers of Elements in Array
A = list(map(int,input().split()))
B = list(map(int,input().split()))
Lis = [] #New List
Sucess = 0
for i in range(N):
Lis.append(A[i])
if(len(set(Lis))>=B[i]):
Lis = sorted(Lis,key=Lis.count,reverse = True)
Set = []
for S in Lis:
if S not in Set:
Set.append(S)
if(len(Set)==B[i]):
break
for K in range(B[i]):
Lis.remove(Set[K])
Sucess += 1
print(Sucess)
Input
1
4
1 1 2 3
3 2 3 2
Output
1
How can i optimize this code further?

Related

Python find index of last element smaller than number

I have a list of numbers from 0 to 3 and I want to remove every number that is smaller than 2 xor is not connected to the last 3 in the list. It is also going to be done about 200 Million times so it should preferably perform well. For example, I could have a list like that:
listIwantToCheck = [3, 0, 1, 2, 0, 2, 3, 2, 2, 3, 2, 0, 2, 1]
listIWantToGet = [2, 3, 2, 2, 3]
I already have the index of the last 3 so what I would do is:
listIWantToGet = listIWantToCheck[??? : indexOfLastThree + 1]
??? being 4 in this instance. It is the index with the mentioned conditions.
So How do I get the index of the last number smaller than 2?
Nailed it, the index i want is
index = ([0]+[i for i, e in enumerate(listIWantToCheck[:indexOfLastThree]) if e < 2])[-1] + 1
List comprehension is truly beautiful.
I enumerated through the slice and created a list of all indices, which point to a number smaller than 2 and took the last. The 0 in front is added to circumvent an index error, which would occur if there are no elements smaller than 2.
So if i get this right you want to get the index of the last number smaller than 2 that comes before the last 3.
My approach would be to take the part of the list from index 0 to the index of the last 3 and then reverse the list and check if the number is smaller than 2.
If you however want to get the last 2 of the entire list just reverse it and loop through it the same way
for i in listIWanttoCheck[0:indexOfLastThree].reverse():
if i <2:
return listIWanttoCheck.index(i)
Correct me if I missunderstood your problem

How do I derive this part of the algorithm

I'm a beginner at programming Python and came across this program.
This algorithm is used to reverse a list:
mylist = [1,2,3,4]
reverse = mylist[:]
for i in range(len(reverse)//2):
reverse[i], reverse[len(reverse) -i -1] = reverse[len(reverse) -i -1], reverse[i]
This algorithm is based on the logic that the swapping process will happen only till the len/2 element for lists with even lengths or the len/2 element in case of lists with a odd length because if the swapping process occurred till the last element, the list would remain the same as it was in the beginning.
I understood what the below part does, but how do I derive it, please explain the logic:
reverse[len(reverse) -i -1]
len(reverse) returns the number of elements the list has. To actually use it as an index you need to subtract 1 from it as indices start from 0. Next, we also subtract i from it as we are moving i positions away from both ends of the list and swapping them.
So if i=1 reverse[i] points to 2 while reverse[len(reverse)-i-1 points to 3.
You can just print the contents of these variables:
lst = [1, 2, 3, 4, 5, 6]
for i in range(len(lst)//2):
print(i, len(lst) - i - 1)
This will print
0 5
1 4
2 3
Therefore,
for the index of the first element (i = 0), len(lst) - i - 1 will return the index of the last element (i = 5).
for the index of the second element (i = 1), len(lst) - i - 1 will return the index of the second to last element (i = 4).
And so on.

why the swapping does not take place when indices are 0 and 1?

I have an unordered array consisting of consecutive integers [1, 2, 3, ..., n] without any duplicates. It is allowed to swap any two elements. I need to find the minimum number of swaps required to sort the array in ascending order.
Starting from the first element of the list, I try to put them in their right position (for example if the first element is 7 it should be in the 6th position of the list). To go one by one in the list, I make a copy, and do the swapping in the second list.
a = [4,3,1,2]
b = a[:]
swap = 0
for p in a:
if (p!= b[p-1]):
b[p-1], b[b.index(p)] = b[b.index(p)], b[p-1]
swap+=1
print(swap)
this code works, except for the case that I have to swap two elements in the list whose position is either 0 or 1, in this case . which I don't understand why?? since I'm not exceeding the limit.
Can anyone please explain to me why this happens?
For example, if I print p, two indices where swapping happens, updated list of b and updated number of swaps:
p = 4
idx1= 3 idx2= 0
b= [2, 3, 1, 4]
swap = 1
p = 3
idx1= 2 idx2= 1
b= [2, 1, 3, 4]
swap = 2
p = 1
idx1= 0 idx2= 1
b= [2, 1, 3, 4]
swap = 3
p = 2
idx1= 1 idx2= 0
b= [1, 2, 3, 4]
swap = 4
In this case, you can see that for p = 1, when indices are 0 and 1, the swapping is not taking place.
I changed the order of b[p-1], b[b.index(p)] and I don't have the same problem anymore, but I don't understand the reason.
I have encountered the same problem before, and stucked for a while. The reason to cause this is the order of multiple assignment.
b[p-1], b[b.index(p)] = b[b.index(p)], b[p-1]
Actually multiple assignment is not exactly assign at the same time. pack and unpack mechanism behind this. so it will change b[p-1] first, and b.index(p) in b[b.index(p)] will be find a new index which is p-1 when the case p=1 idx1=0 idx2=1
if you change the assignment order, it will work fine.
b[b.index(p)], b[p - 1] = b[p - 1], b[b.index(p)]
or calculate idx first:
idx1, idx2 = p - 1, b.index(p)
b[idx1], b[idx2] = b[idx2], b[idx1]
I recommend the second version, because first version will do index twice. cost twice time than second version.
you can refer to my related question here: The mechanism behind mutiple assignment in Python
by the way, I think your algorithm is inefficient here, to decrease swap time, but use O(n) index operation, and also copy a array here. I think you can use the same idea, just swap in orignal array.

How to count the number of local maxima in a nested list?

I have a nested list of numbers. Like this one:
[[1,2,3],[3,2,1],[3,1,2],[2,3,1]]
Now, I want to count the number(s) that is bigger than it's previous element and it's front element, it must also has to have an element on both of it's sides. The output should be like this(inside a list):
[0,0,0,1]
The first element of the output list is zero because in the first nested list, it's first element has no other previous element but only 2 in it's front. For the second element(still on the first nested list) it has 1 as it's previous element and 3 as it's front one but the output is zero because it's needs to be greater than both the element in it's front and it's previous one. The third element is is also not valid because it doesn't have a front element, only it's previous one. The same is for the other nested lists except for the last one. In the last nested list 2 and 1 is already not valid, but 3 is, so now we need to check whether if this is higher than it's two elements. Since three is higher, we count +1 for the last nested list.
Another example:
[[1,2,1,3,1],[2,2,2],[2,3,4,3,4,2,3,1]]
The output should be:
[2,0,3]
The first element of the output list is 2 because in the first nested list(the first and last element is already invalid), 2 has both elements and it is also higher than the both. Then, we move on to 1, it also has both elements but it is smaller than the both so it's invalid. 3 is valid because it has both elements and it is also higher. So we count +2 since there are 2 numbers that valid. The second nested list is invalid because the number that has both elements cannot be equal to any of them, it needs to be higher, and the first and last element is already invalid.In the last nested list, the first and last element of it is already invalid, so we start from it's second one, 3, 3 has both elements but it is only higher than it's previous one but is smaller than it's front one. Next, 4 has both elements and it is also higher so it is counted. Next, 3 has both elements but it is smaller than both of them so it's not counted. Next, 4 has both elements and it is also higher than it's elements. Next, 2 has both elements but it is smaller than it's elements so it's not counted. Next, 3 has both elements and it is also higher than the both, so it's also count. Which makes the last element in the output list count +3.
I am sorry if the explanation is too long/lengthy, but is there any way of doing this in Python 3?
Edit:
So far, I have tried this:
listy = [[1,2,3],[3,2,1],[3,1,2],[2,3,1]]
list_hold = []
for x in listy:
for y in x:
if y>y+1 and y>y-1:
list_hold.append(x)
print(list_hold)
But it only return an empty list.
You need a sliding window iterator; something that produces 3 elements in a row from an input sequence; all you then have to do is count the number of such windows where the middle element is larger than the two other elements.
The sliding window problem is already solved: Rolling or sliding window iterator?, using the window() function from the top answer there would then give you:
def count_maxima(l):
# b, the middle value, is larger than both a and c
return sum(a < b > c for a, b, c in window(l, 3))
result = [count_maxima(sublist) for sublist in outerlist]
Demo:
>>> outerlist = [[1,2,3],[3,2,1],[3,1,2],[2,3,1]]
>>> [count_maxima(sublist) for sublist in outerlist]
[0, 0, 0, 1]
>>> outerlist = [[1,2,1,3,1],[2,2,2],[2,3,4,3,4,2,3,1]]
>>> [count_maxima(sublist) for sublist in outerlist]
[2, 0, 3]
My first thought would be to use np.diff. If you have a given list of values, vals, you can use np.diff(vals) to get an array that is negative if the next number is smaller, and positive if the next number is larger
def count_local_maxima(vals):
if len(vals) < 3:
return 0
diffs = np.diff(vals)
return np.sum((diffs[:-1]>0) & (diffs[1:]<0))
result = [count_local_maxima(sublist) for sublist in mainlist]

Get the pairs of values from a list according to a condition without elements repeating

I have a list of integers like:
1 3 4 4 9 7 10 (the number of elements is between 1 and 200000)
and an integer variable D, it lies between 0 and 10^9.
Let it be 5 for example.
I need to count how many pairs in the list have a difference between each other not bigger than a variable D but the tricky part is that if I took the zero element with value 1 and the first element with the value 3(the difference between them meets the condition) I can't use these elements of a list again.
For example for the sequence above the answer is 3 pairs: (1,3) (4,4) (7,9)
I wrote a code which seems to be correct but I need a hint how to change the input sequence and the variable d the way it will output wrong answer
list_of_colors = [1, 3, 4, 4, 9, 7, 10]
d = 5
number_of_pairs = 0
list_of_colors.sort() # the values in the list are not always sorted
i = 0
while True:
if i >= len(list_of_colors):
break
if i != len(list_of_colors) - 1:
# if the number i in list and i+1 is the same or difference between them not greater than a variable d...
if (int(list_of_colors[i]) == int(list_of_colors[i + 1])) or abs(int(list_of_colors[i]) - int(list_of_colors[i + 1])) <= d:
#print list_of_colors[i]," ",list_of_colors[i + 1]
number_of_pairs += 1 # increasing the number of the acceptable pairs
i += 2 # jump over two elements, we already counted them
continue
i += 1
print number_of_pairs
I need another algorithm to compare it with the results of my algorithm on the various range of the input sequence and the variable d
Suggest your ideas please
I have a greedy solution for this problem:
Sort the input sequence.
Parse the sorted sequence as follows:
For ith element in the sequence,
if |a[i+1]-a[i]| <= D,
then pair up the elements. Proceed to process i+2th element.
else
proceed to process i+1th element.
My solution here is to first "clean" the list what means I made the number of elements even. Then I've converted the list into a list of tuples (pairs).
My result for this example is 3 pairs in order to your condition.
list_of_colors = [1, 3, 4, 4, 9, 7, 10]
d = 5
number_of_pairs = 0
list_of_colors.sort() # the values in the list are not always sorted
# remove the last element if the number of elements is odd
if len(list_of_colors) % 2 != 0:
list_of_colors = list_of_colors[:-1]
# create a list of tuples
list_of_colors = [tuple(list_of_colors[i:i+2]) for i in range(0, len(list_of_colors), 2)]
for i in list_of_colors:
if (int(i[0]) == int(i[1])) or abs(int(i[0])) - int(i[1]) <= d:
number_of_pairs += 1
print number_of_pairs

Categories

Resources