找到具有最佳复杂性的数组中唯一连续增加的子序列的数量

Find the number of unique consecutively increasing subsequences in an array with best complexity

假设给定一个数组 [1, 2, 3, ..., n]。现在随机洗牌。最好的方法是什么(就时间和 space 复杂性而言,在打乱后的数组中找到唯一连续增加的子序列的数量?

例如,a=[1,2,3,6,5,4,7,8,9] 有3个这样的子序列: [1,2,3,4], [6,7,8,9], [5]。 ([5] 简单地满足定义)

提前致谢。

编辑:我在想的一种方法是,每当我们遇到一个新元素时,检查它是否是前一个元素的+1,如果不是,则将其放入一个新数组中。但是当有很多这样的数组时,检查下一个元素是否是任何现有数组的最后一个元素的 +1 需要更长的时间。所以 space 复杂度是 n,但是在最坏情况下 a=[n,n-1,n-2,...,1] 所花费的时间是 1 + 2 + 3 +...+ n- 1=O(n^2)。但可能有更好的方法。

编辑 2:抱歉,我刚刚意识到能够输出这些子序列的显式形式也很重要(如给出的示例所示)。所以有两种最好的复杂度情况,一种用于计算数量,另一种用于输出显式。

我想出了这个(在 Java):

public int countSubSequences(int[] array){
    int numberOfSubSequences = 0;
    for (int i = 0; i < array.length-1; i++) {
        if(array[i]>array[i+1]){
            numberOfSubSequences++;
        }
    }
    numberOfSubSequences++;
    return numberOfSubSequences;
}
   

我只是遍历数组并检查数组中的下一个元素是否小于我的当前元素。如果是这种情况,则当前元素是子序列的末尾,我们可以增加我们的计数。在返回之前我们也需要递增,因为数组的末尾也是最后一个子序列的末尾。

时间复杂度是线性的,所以 O=(n) 和 space 复杂度应该是常数 O=(1) 因为我们不需要记住使用此方法的子序列来计算它们。

您可以通过计算连胜 开始 来计算连胜。值 x 是连胜的开始,前提是您之前没有见过 x - 1。在您的示例中,这是 1、6 和 5。需要 O(n) 时间和 space.

a = [1,2,3,6,5,4,7,8,9]

streaks = 0
seen = set()
for x in a:
    if x - 1 not in seen:
        streaks += 1
    seen.add(x)

print(streaks)

输出,Try it online!

3

可以是 O(1) space 如果你允许修改 a (例如,记住 x 就像通过否定 a[x-1] 看到的那样)。

a = [1,2,3,6,5,4,7,8,9]

streaks = 0
for x in map(abs, a):
    if a[x-2] > 0:
        streaks += 1
    a[x-1] *= -1

print(streaks)

输出,Try it online!

3

一个版本收集了条纹,O(n) 时间和space:

a = [1,2,3,6,5,4,7,8,9]

streaks = {}
for x in a:
    streak = streaks.pop(x - 1, [])
    streak.append(x)
    streaks[x] = streak

print(*streaks.values())

输出,Try it online!

[5] [1, 2, 3, 4] [6, 7, 8, 9]