Python:如何有效地检查序列是否几乎增加

时间:2017-05-31 01:23:52

标签: python performance python-3.x

代码的目标是查看序列是否几乎增加,也就是说,可以通过删除单个元素来严格增加序列。

例如:如果索引1处的元素被删除,[1, 3, 2, 3]将严格增加。 [1, 2, 1, 2]几乎没有增加,因为如果您删除了第一个' 2',那么[1, 1, 2]就不会严格增加。

对于长度为2 <= len <= 10^5的序列,我的代码必须在4000毫秒以下工作。它可能会被很长的序列所吸引。

以下是代码:

def almostIncreasingSequence(sequence):
    for i in range(len(sequence)):
        c = sequence.pop(i)
        if sequence == sorted(sequence):
            for item in sequence:
                if sequence.count(item) != 1:
                    break
            else:
                return True
        sequence.insert(i, c)
    return False

3 个答案:

答案 0 :(得分:1)

你的“几乎增加”的条件可以用以下两条规则来改写:

  1. 列表中最多只有一个位置i不满足ai < ai+1
  2. 该位置周围的元素满足条件ai < ai+2
  3. 这是一个可以在O(n)时间内轻松评估的问题:

    def almostIncreasingSequence(sequence):
        iterator = iter(enumerate(sequence))
        prev = next(iterator)
        found = False
        for item in iterator:
            if item[1] <= prev[1]:
                if found:
                    return False
                if prev[0] > 0 and item[0] < len(sequence) - 1 \
                               and sequence[prev[0] - 1] >= item[1]:
                    return False
                found = True
            prev = item
        return True
    

    如果你被允许使用numpy:

    def almostIncreasingSequence(sequence):
        ind = np.where(np.diff(sequence) <= 0)[0]
        if len(ind) > 1:
            return False
        if len(ind) == 1 and (ind[0] == 0 or ind[0] == len(sequence) - 2):
            return True
        if len(ind) == 0:
            return True
        return sequence[ind[0] + 1] > sequence[ind[0] - 1]
    

    选择树是为了清楚起见。它可以重写为单个return语句:

    return len(ind) == 0 or \
               (len(ind) == 1 and (ind[0] == 0 or \
                                   ind[0] == len(sequence) - 1 or \
                                   sequence[ind[0] - 1] < sequence[ind[0] + 1]))
    

    这两种解决方案都能对[6, 5, 6, 7][1, 2, 3, 1]等边缘情况做出正确反应。

答案 1 :(得分:0)

计算sequence中相邻元素的差异,并找出它不会增加的频率(即差异不是正的频率):

def almost_increasing(seq):
    if type(seq)==type([]):
        seq = np.array(seq)
    diff = seq[1:] - seq[:-1]  # differences of neighboring elements
    indices = np.where(diff <= 0)[0]
    if len(indices) == 0: return True  # increasing sequence, case 1
    elif len(indices) == 1 and indices[0] == len(seq) - 2: return True  # non-increase only at last element, case 2
    elif len(indices) == 1 and indices[0] == len(seq) - 1 and seq[-3] < seq[-1]: return True  # non-increase only at forelast element, case 3
    elif len(indices) == 1 and seq[indices[0]-1] < seq[indices[0]+1]: return True  # case 4
    elif len(indices) == 1 and seq[indices[0]] < seq[indices[0]+2]: return True  # case 5
    else: return False

# For understanding, maybe insert print(indices)
print(almost_increasing([1,2,3]))  # case 1
print(almost_increasing([1,2,3,4,1]))  # case 2
print(almost_increasing([1,2,3,1,4]))  # case 3
print(almost_increasing([1,3,2,3]))  # case 4
print(almost_increasing([1,2,1,4]))  # case 5
print(almost_increasing([1,2,1,2]))

# performance
import time
start = time.clock()
almost_increasing(np.random.random(100000))
stop = time.clock()
print(stop-start)

案例4和5的不同之处在于从序列中删除的元素的选择。

答案 2 :(得分:-1)

如果你提供一些测试会很棒:但是我尝试了一些优势,当大小超过3时,重要的是要关注连续性。只需要区分列表并确保n-3是1。希望我没有误会

import itertools
import numpy as np

def ais(sequence):
    if len(sequence) < 3:  # trivial cases for length 1 and 2 
        return True
    if len(sequence)==3:  # can afford a lazy look
        for perm in itertools.permutations(sequence):
            if perm[1:][1]-perm[1:][0] == 1:
                return True
        return False
    else:
        return list(np.diff(sequence)).count(1) == (len(sequence)-3)