如果你关心的话,背景如果没有,请跳过它:
我今天正在为一个项目录制一些音频,一次做一段。如果我把段落搞砸了,我会把它重新整理,直到我把它弄好,然后转到下一段。当我将它们加载到计算机上时,我需要找到每个段落的最后一个录音。在不知道我为特定段落录制的录音数量的情况下,我该如何解决这个问题呢? (当算法潜入你的日常生活时,你不喜欢它吗?)
在算法术语中,您有一个元素数组,其中每个元素后跟另一个相同类型的元素,或者完全不同的元素。查找序列的每个最后一个元素(正确录制的音频剪辑)。
问题:
所以你有一个对象数组,其中每个元素都有一个id字段,其中每个id都在下面的列表中。我想要最后一个id的对象,比如id的数组:
aabbbbbccddddddddddddddeefffffffffggghhhhiiiijjklmnnnnoo
显然,如果字符串的长度是n并且有n个不同的元素,那么你需要花费n个步骤来计算它。我对通用算法更感兴趣。我可以使用二进制搜索类型算法来完成它,但在不知道输入的情况下我不知道它的运行时间,除了总元素的数量。
另外,知道不同id的数量会改变算法的运行时间吗?这对我来说是一个有趣的问题,我要求的只是满足我的求知欲。
答案 0 :(得分:3)
您应该能够查看第一个ID,并对该ID结束的位置进行二进制搜索。这可以在 O(log n)时间内完成。
然后您前进到下一个元素,并重做二进制搜索以查找该id序列的结束位置。
这会产生复杂度 O(m×log n)的算法,其中 n 是元素的数量, m 的数量是不同的元件。
假设 n / m (特定id的平均元素数)大于 log n ,则会得到一个子线性算法。
如果 n / m 小于 log n ,则最好线性搜索id序列的结尾。
(请注意,整个分析取决于列表按ID排序的事实。排序通常需要与 n×log n 成比例的时间,因此如果您需要对它们进行排序,您可以以及线性算法: - )
答案 1 :(得分:1)
获取数组中的第一个和最后一个元素,并分析此范围内的中间元素。如果找到新的id
,则将最后一个元素放入堆栈(使用id
并找到其到目前为止的位置范围)。否则,在最低和中间元素之间的范围内继续二进制搜索。找到最后一个不同的元素后,弹出堆栈并继续搜索。
时间复杂度为O(m * log(n/m))
,空间复杂度为log(m)
。其中m
是不同值的数量。
答案 2 :(得分:0)
“经典”二分搜索的变体不是分割整个空间,而是以几何方式增长。也就是说,如果您处于 p 的位置,请尝试查看 p +1, p +3, p + 7, p +15,...,直到找到新ID的更改间隔,然后您可以通过经典二进制搜索将其拆分,或者甚至启动新的在最后一个已知的好位置再次成长。
复杂性可能与之前的相同,即O( m * log n ),但这可能更适合您的问题,因为假设相同的ID相对较短( n / m )。
答案 3 :(得分:-1)
二进制搜索在与log(n)成比例的时间内运行。这意味着您添加的元素越多,它的增长就越慢。更准确地说,问题规模的指数增长意味着执行时间的线性增长。换句话说,每当你将录音数量增加一倍时,你需要再听一次,以便找到你想要的东西。
为了进行二进制搜索,您将从录制列表的中间开始,并确定您想要的录制内容是在录制之前还是之后,然后丢弃不包含录制内容的一半。如果录音是正确的段落(但你不知道它是好还是坏),那么将它与之分组并丢弃它之前的所有录音。继续消除一半(通过聆听中间一个),直到你进行1或2次录音。