Detect whether sequence is a multiple of a subsequence in Python

前端 未结 7 1601
轮回少年
轮回少年 2021-02-07 14:44

I have a tuple of zeros and ones, for instance:

(1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1)

It turns out:

(1, 0, 1, 1, 1, 0, 1, 1, 1,          


        
7条回答
  •  无人及你
    2021-02-07 14:57

    The following solution is O(N^2), but has the advantage of not creating any copies (or slices) of your data, as it is based on iterators.

    Depending on the size of your input, the fact you avoid making copies of the data can result in a significant speed-up, but of course, it would not scale as well for huge inputs as algorithms with lower complexity (e.g. O(N*logN)).

    [This is the second revision of my solution, the first one is given below. This one is simpler to understand, and is more along the lines of OP's tuple-multiplication, only using iterators.]

    from itertools import izip, chain, tee
    
    def iter_eq(seq1, seq2):
        """ assumes the sequences have the same len """
        return all( v1 == v2 for v1, v2 in izip(seq1, seq2) )
    
    def dup_seq(seq, n):
        """ returns an iterator which is seq chained to itself n times """
        return chain(*tee(seq, n))
    
    def is_reps(arr, slice_size):
        if len(arr) % slice_size != 0:
            return False
        num_slices = len(arr) / slice_size
        return iter_eq(arr, dup_seq(arr[:slice_size], num_slices))
    
    s = (1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1)
    for i in range(1,len(s)):
        if is_reps(s, i):
            print i, s[:i]
            break
    

    [My original solution]

    from itertools import islice
    
    def is_reps(arr, num_slices):
        if len(arr) % num_slices != 0:
            return False
        slice_size = len(arr) / num_slices
        for i in xrange(slice_size):
            if len(set( islice(arr, i, None, num_slices) )) > 1:
                return False
        return True
    
    s = (1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1)
    for i in range(1,len(s)):
        if is_reps(s, i):
            print i, s[:i]
            break
    

    You can avoid the call to set() by using something like:

    def is_iter_unique(seq):
        """ a faster version of testing len(set(seq)) <= 1 """
        seen = set()
        for x in seq:
            seen.add(x)
            if len(seen) > 1:
                return False
        return True
    

    and replacing this line:

    if len(set( islice(arr, i, None, num_slices) )) > 1:
    

    with:

    if not is_iter_unique(islice(arr, i, None, num_slices)):
    

提交回复
热议问题