Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

find the start position of the longest sequence of 1's

I want to find the start position of the longest sequence of 1's in my array:

a1=[0,0,1,1,1,1,0,0,1,1]
#2

I am following this answer to find the length of the longest sequence. However, I was not able to determine the position.

like image 297
MAS Avatar asked Jul 02 '16 15:07

MAS


People also ask

How to get the longest continuous sequence of 1s?

Given an array of 0s and 1s, find the position of 0 to be replaced with 1 to get longest continuous sequence of 1s. For example : Array- 1,1,0,0,1,0,1,1,1,0,1,1,1 Output - index 9

How do you find the starting point of a consecutive sequence?

Insert all array elements to hash. Check if this element is the starting point of a subsequence. To check this, simply look for arr [i] – 1 in the hash, if not found, then this is the first element a subsequence. If this element is the first element, then count the number of elements in the consecutive starting with this element.

Which is the longest subsequence of consecutive elements?

Input: arr [] = {1, 9, 3, 10, 4, 20, 2} Output: 4 Explanation: The subsequence 1, 3, 4, 2 is the longest subsequence of consecutive elements Input: arr [] = {36, 41, 56, 35, 44, 33, 34, 92, 43, 32, 42} Output: 5 Explanation: The subsequence 36, 35, 33, 34, 32 is the longest subsequence of consecutive elements.

How do you find the previous length of a binary number?

An efficient solution is to walk through the bits in the binary representation of the given number. We keep track of the current 1’s sequence length and the previous 1’s sequence length. When we see a zero, update the previous Length: If the next bit is a 1, the previous Length should be set to the current Length.


5 Answers

Inspired by this solution, here's a vectorized approach to solve it -

# Get start, stop index pairs for islands/seq. of 1s
idx_pairs = np.where(np.diff(np.hstack(([False],a1==1,[False]))))[0].reshape(-1,2)

# Get the island lengths, whose argmax would give us the ID of longest island.
# Start index of that island would be the desired output
start_longest_seq = idx_pairs[np.diff(idx_pairs,axis=1).argmax(),0]

Sample run -

In [89]: a1 # Input array
Out[89]: array([0, 0, 1, 1, 1, 1, 0, 0, 1, 1])

In [90]: idx_pairs # Start, stop+1 index pairs
Out[90]: 
array([[ 2,  6],
       [ 8, 10]])

In [91]: np.diff(idx_pairs,axis=1) # Island lengths
Out[91]: 
array([[4],
       [2]])

In [92]: np.diff(idx_pairs,axis=1).argmax() # Longest island ID
Out[92]: 0

In [93]: idx_pairs[np.diff(idx_pairs,axis=1).argmax(),0] # Longest island start
Out[93]: 2
like image 134
Divakar Avatar answered Oct 19 '22 19:10

Divakar


This seems to work, using groupby from itertools, this only goes through the list once:

from itertools import groupby

pos, max_len, cum_pos = 0, 0, 0

for k, g in groupby(a1):
    if k == 1:
        pat_size = len(list(g))
        pos, max_len = (pos, max_len) if pat_size < max_len else (cum_pos, pat_size)
        cum_pos += pat_size
    else:
        cum_pos += len(list(g))

pos
# 2
max_len
# 4
like image 22
Psidom Avatar answered Oct 19 '22 18:10

Psidom


A more compact one-liner using groupby(). Uses enumerate() on the raw data to keep the starting positions through the analysis pipeline, evenutally ending up with the list of tuples [(2, 4), (8, 2)] each tuple containing the starting position and length of non-zero runs:

from itertools import groupby

L = [0,0,1,1,1,1,0,0,1,1]

print max(((lambda y: (y[0][0], len(y)))(list(g)) for k, g in groupby(enumerate(L), lambda x: x[1]) if k), key=lambda z: z[1])[0]

lambda: x is the key function for groupby() since we enumerated L

lambda: y packages up results we need since we can only evaluate g once, without saving

lambda: z is the key function for max() to pull out the lengths

Prints '2' as expected.

like image 25
cdlane Avatar answered Oct 19 '22 19:10

cdlane


You could use a for loop and check if the next few items (of length m where m is the max length) are the same as the maximum length:

# Using your list and the answer from the post you referred
from itertools import groupby
L = [0,0,1,1,1,1,0,0,1,1]
m = max(sum(1 for i in g) for k, g in groupby(L))
# Here is the for loop
for i, s in enumerate(L):
    if len(L) - i + 2 < len(L) - m:
        break
    if s == 1 and 0 not in L[i:i+m]:
        print i
        break

This will give:

2
like image 20
Moon Cheesez Avatar answered Oct 19 '22 18:10

Moon Cheesez


Another way of doing in a single loop, but without resorting to itertool's groupby.

max_start = 0
max_reps = 0
start = 0
reps = 0
for (pos, val) in enumerate(a1):
    start = pos if reps == 0 else start
    reps = reps + 1 if val == 1 else 0
    max_reps = max(reps, max_reps)
    max_start = start if reps == max_reps else max_start

This could also be done in a one-liner fashion using reduce:

max_start = reduce(lambda (max_start, max_reps, start, reps), (pos, val): (start if reps == max(reps, max_reps) else max_start, max(reps, max_reps), pos if reps == 0 else start, reps + 1 if val == 1 else 0), enumerate(a1), (0, 0, 0, 0))[0]

In Python 3, you cannot unpack tuples inside the lambda arguments definition, so it's preferable to define the function using def first:

def func(acc, x):
    max_start, max_reps, start, reps = acc
    pos, val = x
    return (start if reps == max(reps, max_reps) else max_start,
            max(reps, max_reps),
            pos if reps == 0 else start,
            reps + 1 if val == 1 else 0)

max_start = reduce(func, enumerate(a1), (0, 0, 0, 0))[0]

In any of the three cases, max_start gives your answer (i.e. 2).

like image 42
Douglas Vieira Avatar answered Oct 19 '22 19:10

Douglas Vieira