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

41zrol4v  于 2023-04-13  发布在  Python
关注(0)|答案(3)|浏览(197)

代码的目标是查看序列是否几乎是递增的,也就是说,可以通过删除单个元素使其严格递增。
例如:[1, 2, 1, 2]几乎不会增加,因为如果你删除第一个'2',你会得到[1, 1, 2],它不是 * 严格 * 增加。
对于长度为2 <= len <= 10^5的序列,我的代码必须在4000 ms以下工作。它可能会被很长的序列所占用。
代码如下:

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
23c0lvtd

23c0lvtd1#

你的“几乎增加”的条件可以用以下两个规则来重新措辞:
1.列表中最多有一个位置i不满足ai < ai+1
1.该位置周围的元素满足条件ai < ai+2
这是一个可以在O(n)时间内轻松评估的问题:

def almostIncreasingSequence(sequence):
    iterator = iter(sequence)
    prev = next(iterator)
    found = False
    for item in iterator:
        if item <= prev:
            if found:
                return False
            found = True
        else:
            prev = item
    return True

如果允许使用numpy:

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

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

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

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

bpsygsoo

bpsygsoo2#

计算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的不同之处在于从序列中删除的元素的选择。

9nvpjoqh

9nvpjoqh3#

如果你提供一些测试就好了:p但是我尝试了一些东西,利用了当大小大于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)

相关问题