【问题标题】:Given a sorted array, find the maximum subarray of repeated values给定一个排序数组,找到重复值的最大子数组
【发布时间】:2023-03-26 23:07:01
【问题描述】:

另一个面试问题要求我在尽可能短的计算时间内找到给定排序数组的最大可能重复值子数组。

Let input array be A[1 ... n]
Find an array B of consecutive integers in A such that:
for x in range(len(B)-1):
     B[x] == B[x+1]

我相信最好的算法是将数组分成两半,然后从中间向外,从中间开始相互比较整数,然后从中间找到相同整数的最长应变。然后我将通过将数组分成两半并在两半上调用方法来递归调用该方法。

我的面试官说我的算法很好,但我对算法 O(logn) 的分析是不正确的,但从未有时间告诉我正确答案是什么。我的第一个问题是这个算法的 Big-O 分析是什么? (请尽可能多地展示工作!Big-O 不是我的强项。)我的第二个问题纯粹是出于好奇,是否有更省时的算法?

【问题讨论】:

  • 我对你的问题感到很困惑。你能更详细地描述面试官的意思吗? (什么是“应变”?)您能否更详细地描述您的解决方案? (可能使用伪代码。)
  • 更多细节未注明日期。我基本上使用了分而治之。
  • 请修改您的标题,以便对本网站的未来用户更有用。
  • 是的,谢谢。我对确切措辞的记忆很模糊。

标签: algorithm complexity-theory big-o


【解决方案1】:

对于这个问题你能做的最好的就是O(n) 解决方案,所以你的算法不可能既正确又正确O(lg n)

例如,考虑数组不包含重复元素的情况。要确定这一点,需要检查每个元素,检查每个元素是O(n)

这是一个简单的算法,可以找到重复元素的最长子序列:

start = end = 0
maxLength = 0
i = 0
while i + maxLength < a.length:
    if a[i] == a[i + maxLength]:
        while i + maxLength < a.length and a[i] == a[i + maxLength]:
            maxLength += 1
        start = i
        end = i + maxLength
    i += maxLength

return a[start:end]

如果您有理由相信子序列会很长,您可以将maxLength 的初始值设置为一些启发式选择的值以加快处理速度,然后如果找不到更短的序列(即在第一遍之后你最终得到end == 0。)

【讨论】:

  • 应该有一个比 O(n) 更严格的界限。 OP 的算法听起来比从第一个元素扫描到最后一个元素更有效
  • 我们在这里讨论的是最坏情况下的复杂性。在最坏的情况下(即每个元素都是唯一的)您必须检查每个元素 = O(n)
  • 你忘了说你的解决方案的时间复杂度是多少。
  • @svick 这是O(n)。在最坏的情况下maxLength1i += maxLength 只是变成i += 1
【解决方案2】:

我想我们都同意,在最坏的情况下,所有 A 都是唯一的,或者所有 A 都相同,您必须检查数组中的每个元素以确定没有重复项或确定所有数组包含一个数字。就像其他海报所说的那样,那将是O(N)。我不确定分治法在这方面对您的算法复杂性有多大帮助,尽管您可以通过使用递归来稍微简化代码。当您可以丢弃大部分输入(例如二进制搜索)时,分而治之确实有助于减少 Big O,但在您可能必须检查所有输入的情况下,它不会有太大不同。

我假设这里的结果是您只是返回您找到的最大 B 的大小,尽管您可以轻松地修改它以返回 B。

所以在算法方面,鉴于 A 已排序,我不确定是否会有比按顺序遍历数组更快/更简单的答案。似乎最简单的答案是有 2 个指针,一个从索引 0 开始,一个从索引 1 开始。比较它们,然后将它们都递增;每次它们相同时,您向上勾选一个计数器,为您提供B 的当前大小,当它们不同时,您将该计数器重置为零。您还保留了一个变量来表示迄今为止找到的 B 的最大大小,并在每次找到更大的 B 时更新它。

【讨论】:

  • 同意最坏的情况,“所有唯一”,成本 O(N)。但是“都一样”可以立即从 A[1]==A[n];这是 O(1),我认为这是最好的情况。
【解决方案3】:

在此算法中,n 元素被访问,每个被访问元素的计算次数是恒定的,因此运行时间为O(n)

给定排序数组A[1..n]:

max_start = max_end = 1
max_length = 1
start = end = 1
while start < n
    while A[start] == A[end] && end < n
        end++
    if end - start > max_length
        max_start = start
        max_end = end - 1
        max_length = end - start
    start = end 

【讨论】:

  • 你最好从end = start + max_length开始而不是end = start + 1。它仍然是O(n),但大多数时候它更快。
  • 你是对的。这个特定算法的重点是简单,以便更容易看出数组中的每个元素是如何不断进行额外操作的。
【解决方案4】:

假设最长连续整数的长度仅为 1,您将扫描包含 n 个项目的整个数组 A。因此,复杂度不是以 n 为单位,而是以 len(B) 为单位。

不确定复杂度是否为 O(n/len(B))。

检查 2 边缘情况

- 当 n == len(B) 时,您会得到即时结果(仅检查 A[0] 和 A[n-1] - 当 n == 1 时,得到 O(n),检查所有元素 - 正常情况下,我懒得写算法分析了……

编辑

鉴于事先不知道len(B),我们必须采取最坏的情况,即O(n)

【讨论】:

  • 这个答案是不正确的,计算复杂度等级的方式是相对于输入元素的数量,并且默认指的是算法的最坏情况运行时间,即除非另有说明。如果不是,我可以说我的(蛮力)算法破解符合标准的 AES 加密的运行时间是 O(1),因为它可能会非常幸运并首先测试正确的密钥......跨度>
  • 因试图定义更严格的界限而被否决? :( OP 的算法绝对比线性搜索好,并且绝对依赖于 len(B)
  • @lol 如果考虑到 AES 加密存在缺陷并且倾向于以连续方式重复使用密钥,并且您编写了利用该模式的破解程序,那么您的算法仍然是 O(n) 吗?还是取决于有多少连续重复使用的密钥?
  • "if given that..." 是假设一个前提,当你写下你必须小心不要实质性地改变问题。数学家在这类陈述前面加上“不失一般性”,以澄清他们在假设前提时知道自己在做什么。我要说的是,AES 破解永远不会是 O(1) 或 O(n) ...... n 甚至会是......? (请不要回答)
猜你喜欢
  • 2015-09-27
  • 2015-03-12
  • 1970-01-01
  • 2019-06-04
  • 1970-01-01
  • 1970-01-01
  • 2011-10-27
  • 1970-01-01
  • 2019-02-02
相关资源
最近更新 更多