Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 检查序列是否包含非连续子序列的最快方法?_Python_Python 3.x_Algorithm_Time Complexity - Fatal编程技术网

Python 检查序列是否包含非连续子序列的最快方法?

Python 检查序列是否包含非连续子序列的最快方法?,python,python-3.x,algorithm,time-complexity,Python,Python 3.x,Algorithm,Time Complexity,假设给出了两个元素列表,A和B。我想检查A是否包含B的所有元素。具体来说,元素必须以相同的顺序出现,并且它们不需要是连续的。如果是这种情况,我们说B是a的子序列 以下是一些例子: A = [4, 2, 8, 2, 7, 0, 1, 5, 3] B = [2, 2, 1, 3] is_subsequence(A, B) # True 我找到了一个非常优雅的方法来解决这个问题(请参阅): 我现在想知道这个解决方案在输入量可能非常大的情况下是如何工作的。假设我的列表包含数十亿个数字 上面代码的复杂

假设给出了两个元素列表,
A
B
。我想检查
A
是否包含
B
的所有元素。具体来说,元素必须以相同的顺序出现,并且它们不需要是连续的。如果是这种情况,我们说
B
a
的子序列

以下是一些例子:

A = [4, 2, 8, 2, 7, 0, 1, 5, 3]
B = [2, 2, 1, 3]
is_subsequence(A, B) # True
我找到了一个非常优雅的方法来解决这个问题(请参阅):

我现在想知道这个解决方案在输入量可能非常大的情况下是如何工作的。假设我的列表包含数十亿个数字

  • 上面代码的复杂性是什么?最坏的情况是什么?我试着用非常大的随机输入测试它,但它的速度主要取决于自动生成的输入
  • 最重要的是,是否有更有效的解决方案?为什么这些解决方案比这个更有效

您找到的代码为
A
创建迭代器;您可以将其视为指向
a
中要查看的下一个位置的简单指针,而
中的
会在
a
上向前移动指针,直到找到匹配项。它可以多次使用,但只能向前移动;在
中多次对单个迭代器使用
包含测试时,迭代器不能后退,因此只能测试“仍要访问”值是否等于左侧操作数

在上一个示例中,使用
B=[2,7,2]
,会发生以下情况:

  • it=iter(A)
    A
    列表创建迭代器对象,并将
    0
    存储为下一个要查看的位置
  • all()
    函数测试iterable中的每个元素,如果发现这样的结果,则尽早返回
    False
    。否则它会继续测试每个元素。在这里,测试在it
调用中重复
x,其中
x
依次设置为
B
中的每个值
  • x
    首先设置为
    2
    ,因此测试其中的
    2
    • it
      设置为下次查看
      A[0]
      。这是4,不等于
      2
      ,因此内部位置计数器增加到1
    • A[1]
      2
      ,这是相等的,因此其中的
      2
      此时返回
      True
      ,但不是在增加
      2
      的“下一个要查看的位置”计数器之前
  • 其中的
    2
    为真,因此
    all()
    继续
  • B
    中的下一个值是
    7
    ,因此测试其中的
    7
    • it
      设置为下次查看
      A[2]
      。这是
      8
      ,而不是
      7
      。位置计数器增加到
      3
    • it
      设置为下次查看
      A[3]
      。这是
      2
      ,而不是
      7
      。位置计数器增加到
      4
    • it
      设置为下次查看
      A[4]
      。这是
      7
      ,等于
      7
      。位置计数器增加到
      5
      ,并返回
      True
  • 其中的
    7
    为真,因此
    all()
    继续
  • B
    中的下一个值是
    2
    ,因此测试其中的
    2
    • it
      设置为下次查看
      A[5]
      。这是
      0
      ,而不是
      2
      。位置计数器增加到
      6
    • it
      设置为下次查看
      A[6]
      。这是
      1
      ,而不是
      2
      。位置计数器增加到
      7
    • it
      设置为下次查看
      A[7]
      。这是
      5
      ,而不是
      2
      。位置计数器增加到
      8
    • it
      设置为下次查看
      A[8]
      。这是
      3
      ,而不是
      2
      。位置计数器增加到
      9
    • 没有
      A[9]
      ,因为
      A
      中没有那么多元素,因此返回
      False
  • 其中的
    2
    False
    ,因此
    all()
    通过返回
    False
    结束
  • 您可以使用迭代器验证这一点,并观察其副作用;在这里,我使用
    print()
    写出给定输入的下一个值:

    >>> A = [4, 2, 8, 2, 7, 0, 1, 5, 3]
    >>> B = [2, 7, 2]
    >>> with_sideeffect = lambda name, iterable: (
        print(f"{name}[{idx}] = {value}") or value
        for idx, value in enumerate(iterable)
    )
    >>> is_sublist(with_sideeffect("  > A", A), with_sideeffect("< B", B))
    < B[0] = 2
      > A[0] = 4
      > A[1] = 2
    < B[1] = 7
      > A[2] = 8
      > A[3] = 2
      > A[4] = 7
    < B[2] = 2
      > A[5] = 0
      > A[6] = 1
      > A[7] = 5
      > A[8] = 3
    False
    
    A=[4,2,8,2,7,0,1,5,3] >>>B=[2,7,2] >>>带_sideeffect=lambda名称,iterable:( 打印(f“{name}[{idx}]={value}”)或值 对于idx,枚举中的值(iterable) ) >>>是子列表(有副作用(“>A”,A),有副作用(A[0]=4 >A[1]=2 A[2]=8 >A[3]=2 >A[4]=7 A[5]=0 >A[6]=1 >A[7]=5 >A[8]=3 假的
    您的问题需要连续测试
    B
    的每个元素,这里没有捷径。您还必须扫描
    A
    ,以测试
    B
    的元素是否按正确的顺序存在。只有在找到
    B
    的所有元素(部分扫描)时,才能宣布胜利;在扫描
    A
    中的所有元素且未找到要测试的
    B
    中的当前值时,才能宣布失败

    因此,假设B的大小总是小于A,那么最好的情况是
    B
    中的所有K个元素都等于
    A
    的前K个元素。最坏的情况是
    B
    的所有元素都不在
    A
    中,并且需要通过
    A
    进行完全扫描。无论
    B
    中存在多少个元素都无关紧要;如果您正在测试K中的元素K,您已经通过
    A
    部分扫描了,必须通过
    A
    完成扫描才能找到
    A = [4, 2, 8, 2, 7, 0, 1, 5, 3]
    B = [2, 1, 6]
    is_subsequence(A, B) # False
    
    A = [4, 2, 8, 2, 7, 0, 1, 5, 3]
    B = [2, 7, 2]
    is_subsequence(A, B) # False
    
    def is_subsequence(A, B):
        it = iter(A)
        return all(x in it for x in B)
    
    >>> A = [4, 2, 8, 2, 7, 0, 1, 5, 3]
    >>> B = [2, 7, 2]
    >>> with_sideeffect = lambda name, iterable: (
        print(f"{name}[{idx}] = {value}") or value
        for idx, value in enumerate(iterable)
    )
    >>> is_sublist(with_sideeffect("  > A", A), with_sideeffect("< B", B))
    < B[0] = 2
      > A[0] = 4
      > A[1] = 2
    < B[1] = 7
      > A[2] = 8
      > A[3] = 2
      > A[4] = 7
    < B[2] = 2
      > A[5] = 0
      > A[6] = 1
      > A[7] = 5
      > A[8] = 3
    False