diff --git a/solutions/300. Longest Increasing Subsequence.md b/solutions/300. Longest Increasing Subsequence.md index c5fe656..f6565d3 100644 --- a/solutions/300. Longest Increasing Subsequence.md +++ b/solutions/300. Longest Increasing Subsequence.md @@ -28,8 +28,7 @@ for all j in [0, i-1]: 为什么要选末尾元素最小的呢,是因为在长度一定的情况下,末尾元素最小的是未来最有可能成为最长序列的候选人。这样,每来一个新的数, 我们便按照以下规则更新这些序列: 1. 如果nums[i]比所有序列的末尾都大,或等于最大末尾,说明有更长的递增序列产生,我们把最长的序列复制一遍,并加上这个nums[i]。 -2. 如果nums[i]比所有序列的末尾都小,说明长度为1的序列可以更新了,更新为这个更小的末尾。 -3. 如果在中间,则更新那个末尾数字刚刚大于等于自己的那个序列,说明那个长度的序列可以更新了。 +2. 否则,我们从前往后找,找到第一个末尾大于等于自己的那个序列,更新这个末尾。 比如这时,如果再来一个9,那就是第1种情况,更新序列为 ``` @@ -40,14 +39,14 @@ for all j in [0, i-1]: 1,3,5,6,9 ``` -如果再来一个3,那就是第3种情况,更新序列为 +如果再来一个3,那就是第2种情况,更新序列为 ``` 1 1,2 1,3,3 1,3,5,6 ``` -如果再来一个0,那就是第2种情况,更新序列为 +如果再来一个0,还是第2种情况,更新序列为 ``` 0 1,2 @@ -55,8 +54,13 @@ for all j in [0, i-1]: 1,3,5,6 ``` -前两种都很好处理,O(1)就能解决,主要是第三种情况,实际上我们观察直到6之前这四个不同长度的升序序列,他们末尾是递增的, -所以可以用二分搜索来找到适合的更新位置。 +我们用一个长度可变的tails数组存储上述所有序列的末尾值(因为我们只用到了末尾值),因此tails是个递增数组,这样在第2种情况进行查找的时候就可以使用二分查找了,使复杂度降为O(nlogn)。 + +注意二分查找有现成的库函数: +* lower_bound(first, last, val): 返回有序数组或容器的[first, last)范围内**第一个大于或等于**val的元素的位置(指针或者迭代器,下同); +* upper_bound(first, last, val): 返回有序数组或容器的[first, last)范围内**第一个大于**val的元素的位置; + +可见这里我们应该使用`lower_bound`。 # C++