查找包含所有元素的最短子数组
假设您有一个数字数组和另一组数字。您必须找到包含所有数字且最简单的最短子数组。
该数组可以有重复项,让我们假设数字集没有。它没有顺序-子数组可以按任意顺序包含数字集。
例如:
Array: 1 2 5 8 7 6 2 6 5 3 8 5Numbers: 5 7
那么最短的子数组显然是Array[2:5]
(Python表示法)。
另外,如果您出于某种原因想要避免对数组进行排序(在线算法),该怎么办?
回答:
回答:
我将写“ 右延伸” 表示将范围的右端点增加1,将“ 左收缩” 表示将范围的左端点增加1。此答案是Aasmund
Eldhuset答案的略有变化。此处的区别在于,一旦我们找到最小的j,使得[0,j]包含所有感兴趣的数字,此后,我们将仅考虑包含所有感兴趣的数字的范围。(有可能以此方式解释Aasmund的答案,但也有可能将其解释为允许由于左收缩而丢失一个有趣的数字,该算法的正确性尚待确定。)
基本思想是,对于每个位置j,我们都将找到终止于位置j的最短满足范围,因为我们知道终止于位置j-1的最短满足范围。
修复了基本情况下的故障。
基本情况:找到最小的j’,使[0,j’]包含所有有趣的数字。通过构造,不可能存在包含所有有趣数字的范围[0,k
<j’],因此我们无需进一步担心它们。现在找到 最小的
最大i,使[i,j’]包含所有有趣的数字(即,保持j’固定)。这是在位置j’处结束的最小满足范围。
为了找到以任意位置j结尾的最小满足范围,我们可以将以j-1结尾的最小满足范围右扩展1个位置。该范围也可能包含所有有趣的数字,尽管它可能不是最小长度。
我们需要考虑的唯一操作是左收缩,它保留了包含所有有趣数字的属性。因此,在保持此属性的同时,应将范围的左端点尽可能提前。当无法再执行左收缩操作时,我们得到的最小长度满足范围以j结尾(因为进一步的左收缩显然不能使范围再次满足),我们完成了。
由于我们对每个最右边的位置j执行此操作,因此我们可以对所有最右边的位置取最小长度范围,以找到整体的最小值。这可以使用嵌套循环来完成,其中j在每个外循环循环中前进。显然,j前进了1
n倍。由于在任何时间点我们都只需要先前范围j的最佳范围的最左位置,因此我们可以将其存储在i中,并随即进行更新。i从0开始,始终在<= j <=
n,并且仅向前进1,这意味着它最多可以向n前进。i和j最多前进n次,这意味着该算法是线性时间。
在下面的伪代码中,我将两个阶段组合成一个循环。只有在达到所有有趣数字的阶段,我们才尝试收缩左侧:
# x[0..m-1] is the array of interesting numbers.# Load them into a hash/dictionary:
For i from 0 to m-1:
isInteresting[x[i]] = 1
i = 0
nDistinctInteresting = 0
minRange = infinity
For j from 0 to n-1:
If count[a[j]] == 0 and isInteresting[a[j]]:
nDistinctInteresting++
count[a[j]]++
If nDistinctInteresting == m:
# We are in phase 2: contract the left side as far as possible
While count[a[i]] > 1 or not isInteresting[a[i]]:
count[a[i]]--
i++
If j - i < minRange:
(minI, minJ) = (i, j)
count[]
并且isInteresting[]
是哈希/字典(如果涉及的数字很小,则为纯数组)。
以上是 查找包含所有元素的最短子数组 的全部内容, 来源链接: utcz.com/qa/422929.html