# 最大递增序列
# 获取最大递增序列长度
# 获取最大递增序列
贪心算发 + 二分法
function getSequence(arr) {
// p解析 [index:value] 长度序列中上一个数据的索引
// 有效数据是从(index=1)开始的
// 记录了长度序列中,arr[index]前一位的索引值
const p = arr.slice()
const result = [0]
let i, j, u, v, c
const len = arr.length // arr长度 len
for (i = 0; i < len; i++) {
// 遍历arr
const arrI = arr[i]
// arrI == 0直接下个 => 默认大于等于0
if (arrI !== 0) {
j = result[result.length - 1] // 当前获取的 最大长度的尾数值索引
if (arr[j] < arrI) {
// 当前arrI大于最后一位记录值
p[i] = j // p[i]记录 未添加新纪录前的 最大长度的尾部索引
result.push(i) // result添加当前索引i
continue
}
// 当前arrI 小于 记录最大值result[result.length - 1]
// [0, (u = result.length - 1)] 任意位置都有可能
// 二分法获取arrI在result中的位置
// u => [0, result.length]范围内
u = 0
v = result.length - 1
while (u < v) {
c = ((u + v) / 2) | 0 // 二分
if (arr[result[c]] < arrI) {
u = c + 1
} else {
v = c
}
}
// u:二分法计算结果; result[u]:检索到的索引([0, result,length - 1]); goal=arr[result[u]]
// arrI <= arr[result[result.length - 1]] => goal必定大于或等于arrI
// arrI < goal 需要替换 => result[u]值,替换成更小的数字arrI的索引index
// arrI === goal 不做处理
if (arrI < arr[result[u]]) {
// u == 0,不需要记录前一个索引数据
if (u > 0) {
p[i] = result[u - 1] // 记录序列中,前一个值的索引
}
result[u] = i // result[u]值,替换成更小的数字arrI的索引index
}
}
}
// result 每个节点都记录了当前位置处(即当前的长度下),最小尾部数值的索引
u = result.length
v = result[u - 1]
while (u-- > 0) {
result[u] = v
v = p[v]
}
return result
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# 文献参考
https://en.wikipedia.org/wiki/Longest_increasing_subsequence