简体   繁体   中英

Compare each element in a list with all the previous consecutive elements

I want to compare every element of the list a with its previous consecutive elements. Each iteration of i in forward direction needs i number of iterations for j in backward direction (Or simply iterate j in reverse from the current index of i) and compare if previous consecutive elements satisfies the condition a[i] >= a[j]. If condition is true increase count by 1 (count++) if condition is fails(ie a[i] < a[j] at any index) append the count to a new list li[] and print li.

I tried the following way but failed:

a = [1,2,3,2,4,6,1,2]
li=[]
count = 0
for i in range(len(a)):
  for j in range(i,0,-1):
    while a[i] >= a[j]:
      count+=1
    li.append(count)
    print(li)

the output should look like this:

1 2 3 1 5 6 1 2

And is there any specific way I can solve this in complexity O(n). Like is there any algorithm to solve the problems which need 2 or more nested loops in a certain method, to optimize time complexity.

This is from the category of look-ahead or look-behind problems that require a stack to solve in linear time:

def smaller_preceding(a):
    stack = []
    result = []
    for i, x in enumerate(a):
        while stack and a[stack[-1]] < x:
            stack.pop()
        # current index minus index of last bigger element!
        result.append(i - (stack[-1] if stack else -1))
        stack.append(i)  
    return result

>>> smaller_preceding([1,2,3,2,4,6,1,2])
[1, 2, 3, 1, 5, 6, 1, 2]

The stack keeps track of indeces of strictly decreasing elements, eg at one point it will be:

[2, 3]  
# stack contains indeces  (0 and 1 have been popped)

corresponding to the elements:

[3, 2]  
# ... of decreasing elements (... because 1 and 2 were smaller than 3)

The reasoning is that for every element x in a , you know you can completely forget about all smaller previous elements, as you will never "get past" x when looking back later on (if any smaller elements are smaller than a future element, so will be x !).

You can easily verify that the for -loop has n iterations. Furthermore, one can see that the while -loop also has at most n iterations (even though it is nested) because every index can only be popped off the stack once. Hence, the whole algorithm is linear in time and space.

Using numpy you can evaluate comparisons for a whole np.array . This saves you a loop. The first step creates arrays containing all indexes with a number greater than tha current value: array([1, 2, 3, 4, 5] (for index 6 of the original list).
In the second step, empty arrays are added to li as currenrent index+1 idx+1 since that's how far back the point would have to go (until start of the list). If the array is non-empty, the difference between idx and the biggest value (which is the rightmost index in the index -array) will be added. Again, this is how far the pointer would have to move.

import numpy as np

a = np.array([1, 2, 3, 2, 4, 6, 1, 2])
li = []

for idx, val in enumerate(a):
    index = np.where(a[0:idx+1] > val)
    if np.size(index) == 0:
        li.append(idx+1)
    else:
        li.append(idx - np.max(index))
    
print(li)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM