Example: 3 1 2 7 5 8 6 9 4
v1.0.0
Cycle from front to back to find all the possibilities
const arr = [3, 1, 2, 7, 5, 8, 6, 9, 4]
for (let i = 0; i < arr.length; i++) {
const n = arr[i]
console.log(i, n)
// todo
}
i = 0, longest possible combination:
3 ... // i = 0, n = 3
i = 1, longest possible combination:
3 ... // i = 0, n = 3
1 ... // i = 1, n = 1
i = 2, longest possible combination:
3 ... // i = 0, n = 3
1 ... // i = 1, n = 1
1 2 ... // i = 2, n = 2
And so on:
i = 9, final combination:
0 1 2 3 4 // 序号
3 // i = 0, n = 3
1 // i = 1, n = 1
1 2 // i = 2, n = 2
1 2 7 // i = 3, n = 7
1 2 5 // i = 4, n = 5
1 2 7 8 // i = 5, n = 8
1 2 5 8
1 2 5 6 // i = 6, n = 6
1 2 7 8 9 // i = 7, n = 9
1 2 5 8 9
1 2 5 6 9
1 2 4 // i = 8, n = 4
The longest increasing subsequence found is 1 2 7 8 9, 1 2 5 8 9, 1 2 5 6 9
v2.0.0
we can find out that
1 2 7 ...
1 2 5 ...
The possibility that 1 2 5 can bring includes all the possibilities that 1 2 7 can bring
1 2 5 8 ...
1 2 5 6 ...
The possibilities that 1 2 5 6 can bring include all the possibilities that 1 2 5 8 can bring
So we only need to use the minimum value under the same sequence number
Take i = 5, n = 8 as an example:
0 1 2 // 序号
3 ...
1 ...
1 2 ...
1 2 7 ...
1 2 5 ...
become
3 ...
1 ...
1 2 ...
1 2 7 ...
1 2 5 ...
1 2 5 8 ...
Serial number 2, the corresponding value [7, 5], the minimum value is 5, only 1 2 5 is used here
The final combination of the above:
3 // i = 0, n = 3
1 // i = 1, n = 1
1 2 // i = 2, n = 2
1 2 7 // i = 3, n = 7
1 2 5 // i = 4, n = 5
1 2 5 8 // i = 5, n = 8
1 2 5 6 // i = 6, n = 6
1 2 5 6 9 // i = 7, n = 9
1 2 4 // i = 8, n = 4
The longest increasing subsequence is found to be 1 2 5 6 9. When the data is too large, the number of loops is greatly reduced
Note: If we want to find all the possibilities, we can only sacrifice performance, but in many cases, we only need to find the longest one of them, for example: Vue's virtual node comparison
v3.0.0
In the previous example, each time we need to find the smallest bit under the corresponding serial number, and then compare it. In fact, we can record the minimum value under each serial number in an array (min_arr).
0 1 2 3 4 // 序号
3 // i = 0, n = 3, min_arr = [3]
1 // i = 1, n = 1, min_arr = [1]
1 2 // i = 2, n = 2, min_arr = [1, 2]
1 2 7 // i = 3, n = 7, min_arr = [1, 2, 7]
1 2 5 // i = 4, n = 5, min_arr = [1, 2, 5]
1 2 5 8 // i = 5, n = 8, min_arr = [1, 2, 5, 8]
1 2 5 6 // i = 6, n = 6, min_arr = [1, 2, 5, 6]
1 2 5 6 9 // i = 7, n = 9, min_arr = [1, 2, 5, 6, 9]
1 2 4 // i = 8, n = 4, min_arr = [1, 2, 4, 6, 9]
From v2.0.0, we only need to compare with the minimum value of each serial number, that is, the current n is directly compared with min_arr
Ideas:
- If the current n is larger than the last item of min_arr, put it directly at the end, such as: i = 3, n = 7, 7 is larger than 2, and 7 is placed directly after 2
- If the current n is smaller than the last item of min_arr, loop min_arr from back to front until you find an item smaller than n, and put n behind it. At this time, the original item behind it must be larger than n, so replace the original item behind it. Item; such as: i = 8, n = 4, keep looking forward, 2 is smaller than 4, stop the loop, 4 is placed behind 2, the original 5 after 2 must be larger than 4, otherwise it should end at 5 , so directly replace the original 5 (the code will use the binary search method )
v4.0.0
At this time, we found that although the final value of min_arr is incorrect, the value of the last digit must be correct. If we change our thinking, mark who is behind the last digit, and then mark it forward layer by layer. , does this thing happen, such as
0 1 2 3 4 // 序号
3 // i = 0, n = 3, min_arr = [3], 3前面为undefined
1 // i = 1, n = 1, min_arr = [1], 1前面为undefined
1 2 // i = 2, n = 2, min_arr = [1, 2], 2前面为1
1 2 7 // i = 3, n = 7, min_arr = [1, 2, 7], 7前面为2
1 2 5 // i = 4, n = 5, min_arr = [1, 2, 5], 5前面为2
1 2 5 8 // i = 5, n = 8, min_arr = [1, 2, 5, 8], 8前面为5
1 2 5 6 // i = 6, n = 6, min_arr = [1, 2, 5, 6], 6前面为5
1 2 5 6 9 // i = 7, n = 9, min_arr = [1, 2, 5, 6, 9], 9前面为6
1 2 4 // i = 8, n = 4, min_arr = [1, 2, 4, 6, 9], 4前面为2
First find 9, then 6, then 5, then 2, then 1, then the longest increasing subsequence found is 1 2 5 6 9
finally
In the program, we need to map the value to an index to better find its position
0 1 2 3 4 5 6 7 8 // 索引
3 1 2 7 5 8 6 9 4 // 值
The above v4.0.0 becomes
0 1 2 3 4 // 序号
0 // i = 0, min_arr = [0], 0前面为undefined
1 // i = 1, min_arr = [1], 1前面为undefined
1 2 // i = 2, min_arr = [1, 2], 2前面为1
1 2 3 // i = 3, min_arr = [1, 2, 3], 3前面为2
1 2 4 // i = 4, min_arr = [1, 2, 4], 4前面为2
1 2 4 5 // i = 5, min_arr = [1, 2, 4, 5], 5前面为4
1 2 4 6 // i = 6, min_arr = [1, 2, 4, 6], 6前面为4
1 2 4 6 7 // i = 7, min_arr = [1, 2, 4, 6, 7], 7前面为6
1 2 8 // i = 8, min_arr = [1, 2, 8, 6, 7], 8前面为2
First find the index 7, then 6, then 4, then 2, then 1. At this time, the index is 1 2 4 6 7, and the corresponding longest increasing subsequence value is 1 2 5 6 9
source code
function getSequence(arr:number[]) {
const len = arr.length
const min_arr = [0] // 存储最小的索引,以索引0为基准
const prev_arr = arr.slice() // 储存前面的索引,slice为浅复制一个新的数组
let last_index
let start
let end
let middle
for (let i = 0; i < len; i++) {
let arrI = arr[i]
// 1. 如果当前n比min_arr最后一项大
last_index = min_arr[min_arr.length - 1]
if (arr[last_index] < arrI) {
min_arr.push(i)
prev_arr[i] = last_index // 前面的索引
continue
}
// 2. 如果当前n比min_arr最后一项小(二分类查找)
start = 0
end = min_arr.length - 1
while(start < end) {
middle = (start + end) >> 1 // 相当于Math.floor((start + end)/2)
if (arr[min_arr[middle]] < arrI) {
start = middle + 1
} else {
end = middle
}
}
if (arr[min_arr[end]] > arrI) {
min_arr[end] = i
if (end > 0) {
prev_arr[i] = min_arr[end - 1] // 前面的索引
}
}
}
// 从最后一项往前查找
let result = []
let i = min_arr.length
let last = min_arr[i - 1]
while(i-- > 0) {
result[i] = last
last = prev_arr[last]
}
return result
}
console.log(getSequence([3, 1, 2, 7, 5, 8, 6, 9, 4]))
// 索引:[ 1, 2, 4, 6, 7 ]
// 值: [ 1, 2, 5, 6, 9 ]
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。