找到序列的最长准常数子序列

时间:2018-04-01 00:22:49

标签: python tree subsequence

我今天早些时候进行了这项测试,我试图过于聪明并且遇到障碍。不幸的是,我陷入了这种精神上的困境并且浪费了太多时间,未通过这部分测试。之后我解决了这个问题,但也许所有人都可以帮助我摆脱最初的困境。

问题定义:

给出了由N个整数(全部为正)组成的无序且非唯一的序列A. A的子序列是通过从A中去除无,部分或全部元素而获得的任何序列。序列的幅度是该序列中最大和最小元素之间的差。假设空子序列的幅度为0.

例如,考虑序列A由六个元素组成,例如:

A[0] = 1
A[1] = 7
A[2] = 6
A[3] = 2
A[4] = 6
A[5] = 4

如果数组的幅度不超过1,则数组A的子序列称为准常数。在上例中,子序列[1,2],[6,6]和[6,6,7]是准常数。子序列[6,6,7]是A中最长的准常数子序列。

现在,找到一个解决方案,给定一个由N个整数组成的非空零索引数组A,返回数组A的最长准常数子序列的长度。例如,给定的序列A如上所述,该函数应返回3,如解释。

现在,我在使用基于排序的方法没有类(我的代码在下面)之后在python 3.6中解决了这个问题,但我最初并不想这样做,因为在大型列表上排序可能非常慢。它似乎应该有一个相对简单的公式作为广度优先的树类,但我无法做到正确。有什么想法吗?

我的无类别排序解决方案:

def amp(sub_list):
    if len(sub_list) <2:
        return 0
    else:
        return max(sub_list) - min(sub_list)

def solution(A):
    A.sort()
    longest = 0
    idxStart = 0
    idxEnd = idxStart + 1
    while idxEnd <= len(A):
        tmp = A[idxStart:idxEnd]
        if amp(tmp) < 2:
            idxEnd += 1
            if len(tmp) > longest:
                longest = len(tmp)
        else:
            idxStart = idxEnd
            idxEnd = idxStart + 1
    return longest

2 个答案:

答案 0 :(得分:3)

我不知道BFS应该如何在这里提供帮助。

为什么不简单地在序列中运行一次并计算每个可能的准常数子序列将包含多少个元素?

from collections import defaultdict

def longestQuasiConstantSubseqLength(seq):
  d = defaultdict(int)
  for s in seq:
    d[s] += 1
    d[s+1] += 1
  return max(d.values() or [0])

s = [1,7,6,2,6,4]

print(longestQuasiConstantSubseqLength(s))

打印:

3

正如所料。

说明:每个非常量准常量子序列由它包含的最大数字唯一标识(只有两个,取较大的一个)。现在,如果您有一个数字s,它可以为最常数ss + 1的准常数子序列做出贡献。因此,只需将+1添加到ss + 1标识的子序列中。然后输出所有计数的最大值。

你不能比O(n)更快,因为你必须至少查看一次输入序列的每个条目。

答案 1 :(得分:2)

正如Andrey Tyukin指出的那样,你可以在O(n)时间内解决这个问题,这比你可能从排序或任何类型的基于树的解决方案获得的O(n log n)时间更好。诀窍是使用字典来计算输入中每​​个数字的出现次数,并使用计数来计算最长的子序列。

我对他有类似的想法,但我的实现略有不同。经过一些测试后,看起来我的方法速度要快得多,所以我将它作为自己的答案发布。它很短!

from collections import Counter

def solution(seq):
    if not seq:     # special case for empty input sequence
        return 0
    counts = Counter(seq)
    return max(counts[x] + counts[x+1] for x in counts)

我怀疑这比Andrey的解决方案更快,因为我们的两个解决方案的运行时间确实需要O(n) + O(k)时间,其中k是输入中不同值的数量(并且n是输入中的值的总数)。我的代码通过将序列移交给O(n)构造函数来非常有效地处理Counter部分,该构造函数在C中实现。可能有点慢(基于每个项目)来处理使用O(k)部分,因为它需要生成器表达式。 Andrey的代码反过来(它为O(n)部分运行较慢的Python代码,并为O(k)部分使用更快的内置C函数)。由于k始终小于或等于n(如果序列具有重复值的 lot ,可能会少得多),我的代码总体上更快。这两种解决方案仍然是O(n),并且两者都应该比为大型输入排序要好得多。