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

Time:10-22

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(i.e 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.

CodePudding user response:

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)

CodePudding user response:

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, e.g. 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.

  • Related