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

问题描述

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

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

提前致谢。

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

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

解决方法

您可以通过计算连续的开始次数来计算连续的次数。如果您以前从未见过 x,则值 x - 1 是连续开始。在您的示例中,这是 1、6 和 5。需要 O(n) 时间和空间。

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)

输出,GNU bash

3

如果允许对 a 进行修改,则可以是 O(1) 空间(例如,记住 x 通过否定 a[x-1] 看到的)。

a = [1,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) 的版本:

a = [1,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,4] [6,9]
,

我想出了这个(在 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) 和空间复杂度应该是常数 O=(1),因为我们不需要记住使用这种方法的子序列来计算它们。