Python find index of last element smaller than number - python

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

Related

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.

How can i optimize this python code to reduce time complexity

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?

Selecting a list slice, reversing it, and updating the list

I'm trying to get some guidance on how to implement this algorithm in python. I'm currently trying to solve adventofcode.com/2017/day/10.
I understand the logic of what needs to be done, but where I'm stuck is implementing this in code specifically taking a selection/slice of a list, reversing it, then "putting it back" into said list.
The example they give is:
Suppose we instead only had a circular list containing five elements, [0, 1, 2, 3, 4] and were given input lengths of [3, 4, 1, 5].
The list begins as [0] 1 2 3 4 (where square brackets indicate the current position).
The first length, 3, selects [0] 1 2) 3 4 (where parentheses indicate the sublist to be reversed).
After reversing that section (0 1 2 into 2 1 0), we get ([2] 1 0) 3 4.
Then, the current position moves forward by the length, 3, plus the skip size, 0: 2 1 0 [3] 4. Finally, the skip size increases to 1.
The second length, 4, selects a section which wraps: 2 1) 0 ([3] 4.
The sublist 3 4 2 1 is reversed to form 1 2 4 3: 4 3) 0 ([1] 2.
The current position moves forward by the length plus the skip size, a total of 5, causing it not to move because it wraps around: 4 3 0 [1] 2. The skip size increases to 2.
I know I will use a for loop for each length, then based on the current "cursor" position, create a slice that starts at the cursor position, and contains the amount of elements that matches the current iteration (in the second example it would be 4). I feel like this needs to be solved using the %, list slicing, and the length of the list but can't figure it out. Any guidance or help would be much appreciated even if it's resources to learn how to solve this versus just the answer. But I'll take anything. Thanks friends.

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.

Cannot understand recursive function Python

I have been looking at the solution for this problem (below) for hours and cannot figure out how the recursion works. Can someone please explain in basic terms how it works.
Since group is appended and then popped, isn't the popped list going to just always be equal to nothing []?
# Given a list of ints, is it possible to choose a group of some of the
# ints, such that the group sums to the given target?
# 0, 2, 4, 8, 10 -> True
# 0, 2, 4, 8, 14 -> True
# 0, 2, 4, 8, 9 -> False
def sum_checker(ints, total, group, index):
if sum(group) > total: # backtracking
return False
if index == len(ints): # BASE CASE
return sum(group) == total
group.append(ints[index])
if sum_checker(ints, total, group, index + 1):
return True
group.pop()
return sum_checker(ints, total, group, index + 1)
ints = [int(input()) for i in range(int(input()))]
total = int(input())
group = []
print(sum_checker(ints, total, group, 0))
isn't the popped list going to just always be equal to nothing []?
Not always. At the third if statement, it recursively adds to the group list, and only when that call stack returns (when the sum of the group exceeds the total, or the index is outside the input range), does the most recent pushed value get popped.
In execution order of the first input , here's the group values
0
0, 2
0, 2, 4
0, 2, 4, 8... Sum is greater than 10, return False
8 is popped, and the previous index increases
0, 2, 4.... The index is out of range, and the group sum is not the total
4 is popped and the previous index increases
0, 2, 8... This is equal to 10, so we return True back up the call stack
At the end of unwinding the recursion, yes the group list will be empty, but the output only requires a boolean, not tracking the group that matches the criteria
Ok. So let's think this question without real code at first. Just think this strategy:
We test each element of ints one by one, checking by picking current value plus previous selection can we get the target sum.
For example, ints= [1, 2, 4, 8], target = 11.
We try to select 1, we don't know if we can get the target before examine other elements, so we continue to check, holding that 1 in your hands.
Now we meet 2, still no idea, just pick and continue.
Same for 4.
Oops, we have sum=1+2+4+8 = 13 > 11. [1,2,4,8] is a bad selection plan. Let's drop from the end and chek if we have other choices. Drop 8.
Now we have sum=1+2+4=7, but we cannot add more elements since we reach the end of ints. Drop 4 to see if more choices are possible.
We now hold 1+2 and should check from 8, That's 11! We made it!
So try this process yourself using pencil and paper. The core idea here is to maintain a what-we-have-selected array, which is group in your code, and then to check if we can reach target based on this selection + new elements. If not, modify the what-we-have-selected array and continue.
Regarding your concern about group being appended and popped. Remember that the statement
if sum_checker(ints, total, group, index + 1):
Starts the search again (just this time with the next index). Say with your example.
sum_checker(
ints=[0, 2, 4, 8],
total=10,
group=[],
index=0
)
The first time we hit group, we append 0 to group, so we're then calling sum_checker with the arguments.
sum_checker(
ints=[0, 2, 4, 8],
total=10,
group=[0],
index=1
)
Then, since group already has one element, we append 2 to group. So we then have:
sum_checker(
ints=[0, 2, 4, 8],
total=10,
group=[0, 2],
index=2
)
Which means, we start filling up group before we get to .pop(). If the sum() of group becomes too big, THEN we do the first .pop(), and start checking again without the last element that was added.

Categories

Resources