2024-09-18 15:08:22 +08:00

65 lines
2.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

function getSequence(arr) {
// 用于记录每个位置的前驱索引,以便最后重建序列
const p = arr.slice();
// 存储当前找到的最长递增子序列的索引
const result = [0];
// 声明循环变量和辅助变量
let i, j, u, v, c;
// 获取输入数组的长度
const len = arr.length;
// 遍历输入数组
for (i = 0; i < len; i++) {
const arrI = arr[i];
// 忽略值为 0 的元素Vue源码中的diff算法对0有特定处理
if (arrI !== 0) {
// 获取当前最长序列中最后一个元素的索引
j = result[result.length - 1];
// 贪心算法部分:如果当前元素大于当前最长序列的最后一个元素,直接添加
if (arr[j] < arrI) {
// 记录当前元素的前驱索引为 j
p[i] = j;
// 将当前元素的索引添加到 result 中
result.push(i);
continue;
}
// 二分查找部分:在 result 中寻找第一个大于等于 arrI 的元素位置
u = 0;
v = result.length - 1;
while (u < v) {
// 取中间位置
c = ((u + v) / 2) | 0;
// 比较中间位置的值与当前值
if (arr[result[c]] < arrI) {
// 如果中间值小于当前值,搜索区间缩小到 [c + 1, v]
u = c + 1;
} else {
// 否则,搜索区间缩小到 [u, c]
v = c;
}
}
// 如果找到的值大于当前值,进行替换
if (arrI < arr[result[u]]) {
// 如果 u 不为 0记录前驱索引
if (u > 0) {
p[i] = result[u - 1];
}
// 更新 result 中的位置 u 为当前索引 i
result[u] = i;
}
}
}
// 重建最长递增子序列
u = result.length;
v = result[u - 1];
while (u-- > 0) {
// 将索引替换为对应的前驱索引
result[u] = v;
v = p[v];
}
// 返回最长递增子序列的索引数组
return result;
}
const list = [2, 1, 5, 3, 6, 4, 8, 9, 7];
const result = getSequence(list);
console.log(result); // [ 1, 3, 5, 6, 7 ] --> [ 1, 3, 4, 8, 9 ]