确定输入列表是否严格增加

时间:2018-03-15 20:34:31

标签: python python-3.x list

我试图弄清楚输入列表是否是一个严格增加的列表。此外,如果从列表中只删除一个元素会导致严格增加的列表,我们仍然认为列表为true。这是我的代码。它似乎有一个索引错误,但我不明白为什么。

 def almostIncreasingSequence(sequence):
    n=len(sequence)
    count=0
    if n<=2:
        return True

    for i in range (n-1):
        #test if the i-th element is bigger or equal to the elements after it. If it is, remove that element, and add one to count 
        for j in range (i+1,n):
            if sequence[i]>=sequence[j]:
                sequence.pop(i)
                count+=1
    #if there is more than one element that has to be taken out, it's false           
    if count>1:
        return False

    return True

4 个答案:

答案 0 :(得分:3)

def almost_increasing_sequence(sequence):
    if len(sequence) < 3:
        return True

    a, b, *sequence = sequence
    skipped = 0
    for c in sequence:
        if a < b < c:  # XXX
            a, b = b, c
            continue
        elif b < c:    # !XX
            a, b = b, c
        elif a < c:    # X!X
            a, b = a, c
        skipped += 1
        if skipped == 2:
            return False
    return a < b


if __name__ == '__main__':
    assert almost_increasing_sequence([]) is True
    assert almost_increasing_sequence([1]) is True
    assert almost_increasing_sequence([1, 2]) is True
    assert almost_increasing_sequence([1, 2, 3]) is True
    assert almost_increasing_sequence([3, 1, 2]) is True
    assert almost_increasing_sequence([1, 2, 3, 0, 4, 5, 6]) is True
    assert almost_increasing_sequence([1, 2, 3, 0]) is True
    assert almost_increasing_sequence([1, 2, 0, 3]) is True
    assert almost_increasing_sequence([10, 1, 2, 3, 4, 5]) is True
    assert almost_increasing_sequence([1, 2, 10, 3, 4]) is True
    assert almost_increasing_sequence([1, 2, 3, 12, 4, 5]) is True

    assert almost_increasing_sequence([3, 2, 1]) is False
    assert almost_increasing_sequence([1, 2, 0, -1]) is False
    assert almost_increasing_sequence([5, 6, 1, 2]) is False
    assert almost_increasing_sequence([1, 2, 3, 0, -1]) is False
    assert almost_increasing_sequence([10, 11, 12, 2, 3, 4, 5]) is False

答案 1 :(得分:3)

好吧,事实证明这个问题 不容易。

如果你想要一个有效的解决方案,我认为你最好的选择可能是类似于longest increasing subsequence problem的算法。

但是在这里,我们并不关心实际上增长最快的子序列 - 我们只需要它的长度。此外,如果我们必须执行n插入,我们可以在维护有序列表时短路(其中n是我们对&#34;无序&#34;元素数量的限制)。

这也很好地概括了n元素&#34;几乎增加&#34;大多数情况下,在大小为n-1M-n-1的列表上执行M二进制搜索,其中M是列表的大小。

import bisect

def almost_increasing(li, n=1):
    if len(li) < 2:
        return True
    ordered_li = [li[0]]
    violator_count = 0
    for ele in li[1:]:
        if ele < ordered_li[0]:
            violator_count += 1
            ordered_li[0] = ele
        elif ele > ordered_li[-1]:
            ordered_li.append(ele)
        else:
            violator_count += 1
            insertion_pos = bisect.bisect_right(ordered_li, ele)
            ordered_li[insertion_pos] = ele
        if violator_count > n: return False
    return True

这个算法背后的想法如下:

  • 我们在列表中移动,并始终保持列表的有序子序列。
  • 当我们到达新元素时

    • 如果该元素无法附加到我们的有序子序列上,则它是一个违反者&#34;不断增加的财产。我们随后使用bisect将其插入正确位置的有序子序列中进行二进制搜索。

    • 否则,我们只是将其附加到我们订购的子序列中并继续。

  • 在每次迭代结束时,如果我们有太多的违规者,我们就可以短路了。否则,在循环完成后,我们保证有一个增加的子序列,其长度在原始列表长度的n之内。

<强>演示

>>> almost_increasing([5, 1, 2, 3, 4])
True
>>> almost_increasing([1, 2, 5, 2, 15, 0, 176])
False
>>> almost_increasing([1, 2, 5, 2, 15, 0, 176], 2)
True

答案 2 :(得分:2)

如果您在Python中编写for i in range(len(some_list)),那么您可能做错了。这确实是失败的原因。 n是在任何处理之前的序列的长度,但该长度可以随着列表中的pop项而改变。

更好的方法是比较每个标记需要删除的标记,并一次完成所有这些标记,或者更好的方法 - 根本不删除它们!这是一个没有得到很好解释的副作用。

您可以通过使用itertools.combinations构建可能严格增加的所有序列的列表,将每对与itertools pairwise配方进行比较,然后缩短只要至少有一个就是电路。

import itertools

def pairwise(iterable):
    (a, b) = itertools.tee(iterable)
    next(b, None)  # advance b
    return zip(a, b)

def almostIncreasingSequence(sequence):
    if not sequence:
        return True
        # in case of empty list
    combos = itertools.combinations(sequence, len(sequence)-1)
    # combos is each ordered combination that's missing one element
    # it is processed as an iterator, so will do no extra work if we can
    # exit early.

    def strictly_increasing(cs):
        return all(a < b for (a, b) in pairwise(cs))

    return any(strictly_increasing(c) for c in combos)

答案 3 :(得分:-1)

您唯一需要做的就是遍历列表,计算sequence[i] > sequence[i+1]的次数。如果它最多发生一次,那么你的列表几乎会单调增加。

def almostIncreasingSequence(sequence):
    count = 0
    for i in range(0, len(sequence) - 1):
        if sequence[i] > sequence[i+1]:
            count += 1
    return count < 2

您也可以避免计数,因为例外的数量很少。一旦找到第二个异常,只需返回False,由初始化为True的布尔变量的值跟踪。

def almostIncreasingSequence(sequence):
    increasing = True
    for i in range(0, len(sequence) - 1):
        if sequence[i] > sequence[i+1]:
            if increasing:
                increasing = False
            else:
                return False
    return True