找到最长的递增序列
给定一个数字序列,您需要从给定的输入中找到最长的递增子序列(不一定是连续的)。
我找到了此链接(维基百科上的最长递增子序列),但需要更多解释。
如果有人可以帮助我理解 O(n log n) 实现,那将非常有帮助。如果您能用一个例子解释该算法,我们将不胜感激。
我也看到了其他帖子,但我不明白的是: L = 0 对于 i = 1, 2, ... n: 二分查找最大正 j ≤ L 使得 X[M[j]] < X[i](如果不存在这样的值,则设置 j = 0) 上面的语句,从哪里开始二分查找呢?如何初始化M[]、X[]?
You are given a sequence of numbers and you need to find a longest increasing subsequence from the given input(not necessary continuous).
I found the link to this(Longest increasing subsequence on Wikipedia) but need more explanation.
If anyone could help me understand the O(n log n) implementation, that will be really helpful. If you could explain the algo with an example, that will be really appreciated.
I saw the other posts as well and what I did not understand is:
L = 0
for i = 1, 2, ... n:
binary search for the largest positive j ≤ L such that X[M[j]] < X[i] (or set j = 0 if no such value exists)
above statement, from where to start binary search? how to initialize M[], X[]?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
一个更简单的问题是找到最长递增子序列的长度。您可以先专注于理解该问题。该算法的唯一区别是它不使用 P 数组。
x 是序列的输入,因此可以将其初始化为:
x = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]
m 跟踪最佳子序列到目前为止找到的每个长度。最好的是最终值最小的那个(允许在其后添加更广泛的值)。长度和结束值是每个子序列需要存储的唯一数据。
m 的每个元素代表一个子序列。对于m[j],
L是迄今为止找到的最长子序列的长度。 m 的前 L 值有效,其余未初始化。 m 可以从第一个元素为 0 开始,其余元素未初始化。 L 随着算法的运行而增加,m 的初始化值的数量也随之增加。
这是一个运行示例。给出每次迭代结束时的 x[i] 和 m (但使用序列的值而不是索引)。
每次迭代中的搜索都会寻找放置 x[i] 的位置。它应该尽可能向右(以获得最长的序列),并且大于其左侧的值(因此它是一个递增序列)。
现在我们知道有一个长度为 6、以 15 结尾的子序列。子序列中的实际值可以通过在循环期间将它们存储在 P 数组中来找到。
检索最佳子序列:
P 为每个数字存储最长子序列中的前一个元素(作为 x 的索引),并随着算法的进展进行更新。例如,当我们处理8时,我们知道它在0之后,因此将8在0之后的事实存储在P中。您可以像链表一样从最后一个数字向后推算以获得整个序列。
因此,对于每个数字,我们都知道它之前的数字。为了找到以 7 结尾的子序列,我们查看 P 并看到:
所以我们有子序列 [0, 1, 3, 7]。
以 7 或 15 结尾的子序列共享一些数字:
因此我们有子序列 [0, 2, 6, 9, 11] 和 [0, 2, 6, 9, 11, 15](最长递增子序列)
A simpler problem is to find the length of the longest increasing subsequence. You can focus on understanding that problem first. The only difference in the algorithm is that it doesn't use the P array.
x is the input of a sequence, so it can be initialized as:
x = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]
m keeps track of the best subsequence of each length found so far. The best is the one with the smallest ending value (allowing a wider range of values to be added after it). The length and ending value is the only data needed to be stored for each subsequence.
Each element of m represents a subsequence. For m[j],
L is the length of the longest subsequence found so far. The first L values of m are valid, the rest are uninitialized. m can start with the first element being 0, the rest uninitialized. L increases as the algorithm runs, and so does the number of initialized values of m.
Here's an example run. x[i], and m at the end of each iteration is given (but values of the sequence are used instead of indexes).
The search in each iteration is looking for where to place x[i]. It should be as far to the right as possible (to get the longest sequence), and be greater than the value to its left (so it's an increasing sequence).
Now we know there is a subsequence of length 6, ending in 15. The actual values in the subsequence can be found by storing them in the P array during the loop.
Retrieving the best sub-sequence:
P stores the previous element in the longest subsequence (as an index of x), for each number, and is updated as the algorithm advances. For example, when we process 8, we know it comes after 0, so store the fact that 8 is after 0 in P. You can work backwards from the last number like a linked-list to get the whole sequence.
So for each number we know the number that came before it. To find the subsequence ending in 7, we look at P and see that:
So we have the subsequence [0, 1, 3, 7].
The subsequences ending in 7 or 15 share some numbers:
So we have the subsequences [0, 2, 6, 9, 11], and [0, 2, 6, 9, 11, 15] (the longest increasing subsequence)
麻省理工学院网站给出了对此问题的最佳解释之一。
http://people.csail.mit.edu/bdean/6.046/dp/
我希望它能消除您所有的疑虑。
One of the best explanation to this problem is given by MIT site.
http://people.csail.mit.edu/bdean/6.046/dp/
I hope it will clear all your doubts.
基于FJB的回答,java实现:
}
based on FJB's answer, java implementation:
}
下面是 O(NLogN) 最长递增子序列的实现:
Below is the O(NLogN) longest increasing subsequence implementation:
虽然迟到了,但这里有一个 JavaScript 实现可以与其他实现一起使用..:)
Late to the party, but here's a JavaScript implementation to go along with the others.. :)
根据@fgb的回答,我使用c++实现了算法来查找最长的严格递增子序列。希望这会有所帮助。
M[i]是长度为i的序列的最后一个元素的索引,P[i]是序列中i的前一个元素的索引,用于打印整个序列。
main() 用于运行简单的测试用例:{0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}。
Based on @fgb 's answer, I implemented the algorithm using c++ to find the longest strictly increasing sub-sequence. Hope this will be somewhat helpful.
M[i] is the index of the last element of the sequence whose length is i, P[i] is the index of the previous element of i in the sequence, which is used to print the whole sequence.
main() is used to run the simple test case: {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}.
O(N lg N)的解决方案来自于扑克牌的耐心排序。我从我的代码注释中发现了这一点,因此在这里分享。我相信大家会更容易理解它是如何工作的。如果你理解得好的话,你还可以找到所有可能的最长递增子序列列表。
https://www.cs.princeton.edu/ course/archive/spring13/cos423/lectures/LongestIncreasingSubsequence.pdf
代码:
代码:
The O(N lg N) solution comes from patience sorting of playing card. I found this from my code comment and hence sharing here. I believe it would be really easier to understand for everyone how it works. Also you can find all possible longest increasing sub-sequence list if you understand well.
https://www.cs.princeton.edu/courses/archive/spring13/cos423/lectures/LongestIncreasingSubsequence.pdf
Code:
Code:
我强烈建议点击此处更详细的解释。我还使用此链接进行以下解释。
该解决方案的总体思路是模仿耐心排序的过程来找到最长的长度递增子序列 (LIS):
构造一个列表,
尾部
。该列表将存储每堆最上面的牌。循环遍历
nums
列表中的每个元素。对于每个元素 x,根据以下规则更新
tails
列表:(1) 如果 x 大于 tails 中的所有元素,则将其追加。
(2) 如果
tails[i-1]
x <=
tails[i]
,用 x 更新tails[i]
。这一步找到每个阶段的最佳最长递增子序列。
请注意,此步骤是使用二分搜索完成的,因为我们可以使用二分搜索来循环
tails
并找到元素 x 的适当位置。tails
列表是最长递增子序列。要查找所有子序列,我们只需在每次迭代时存储尾部列表即可。例如,如果我们有
nums = [4,5,6,3]
,那么tails
列表会像这样增加:总的来说,我们已经迭代了
nums
一次,对于每个元素我们都使用过一次二分查找,因此大 O 将为 O(nlogn)。I strongly recommend to click here for a more detailed explaination. I have also used this link for the following explanation.
The general idea of the solution is to mimic the process of Patience Sort to find the length of Longest Increasing Subsequence (LIS):
Construct a list,
tails
. This list will store the top cards in each pile.Loop through each element in the
nums
list.For each element x, update the
tails
list based on the rules below:(1) If x is larger than all the elements in tails, append it.
(2) If
tails[i-1]
< x <=tails[i]
, updatetails[i]
with x.This step finds the optimal Longest Increasing Subsequence at each stage.
Note that this step is completed using Binary Search, since we can use Binary Search to loop throught
tails
and find the appropriate position for element x.The
tails
list is a Longest Increasing Subsequence. To find all of the subsequences, we can just store the tails list at each iteration.For example, if we have
nums = [4,5,6,3]
, then thetails
list increases like this:Overall, we have iterated through
nums
once, and for every element we have used Binary Search once, so the Big O would be O(nlogn).