寻找最大递增子序列是比较常见的算法,实现方式也不尽相同,此文稍作介绍。

我是算法世界的小学生,因为最近再看 vue3 Diff 有一个寻找最大递增子序列的使用,遂为了弄明白花了些时间并去网上网罗了一些实现方法,但重点分析 这种方法 的实现思路,我认为是比较优秀的方式。


一种好的实现方式分析

这种方式找的是最大递增子序列的索引,而不是项。主要说一下思路:

  1. 遍历数组
  2. arr 拷贝一份(p),遍历过程中用来保存比当前项小的最近项的索引。
  3. result 保存最后的返回值,遍历过程中遇到比 result 最后一项大的 就 push 相应的索引,否者更新result中对应项比当前项大且不相等的一项。注意是索引。
  4. 用一个变量保存在 result 中大于当前项的索引(u,也是找中位数的起始项索引),一个变量保存中位数索引( c )
    一个变量保存取中位数的结束项索引(v)。
  5. 利用 p 修正数组

注意点:

  • p 每次更新都是从当前 result 中找出索引对应的数组项与当前项相比,如果存在比当前项小的项,那么 p 相应的项更新为找出项的在数组的索引。否者不更新。
  • result 仅在遇到相等项时不更新,否者就更新。

文字略显干涩且绕口难以理解,来点图例解析

例子

  • 为了便于理解,result和p里面保存的是项,而不是索引。则result 初始值为 [arr[0]]
  • 浅蓝代表遍历的当前项
  • i 代表遍历的索引值

[2, 7, 10, 6, 3, 1, 10, 1, 1] 的最大递增子列。

i=0,

i=1,

i=2,

i=3, 当前项 current = 6, 6 始终和 result[c] 作比较

  1. u=0,v=2 (result.length-1); c=1; 6<7
  2. u=0,v=1,c=0,6>2
  3. u=1,v=1,循环结束,于是 result[u] = 6, p[3] = 2

总结,result中比当前项大的更新为当前项,result中比当前项小的项用来更新p相应的项。

i=4,

  • 3>result中的2, 将 2 之后的一项更新为3 。并且将 result 中的 2 更新 p 相应的项

i=5,

  • 当前项小于 result 中的最小项,p 不做更新。result 第一项 2 更新为 1

i=6,

  1. u=0, v=2; 10>result[1]= 3;
  2. u=2v=2; 10不大于result[2] = 10;且不小于10,那么 p不更新(u虽然大于0,但是10不小于result[2])。result也不更新

i=7,

  • u最后=0。1不大于result中最小项,则p不更新,又因为1不大于result最大项,result也不更新。

i=8, 处理同 i=7 ,均不更新,这里我添加了result的对应关系

最后由 presult 进行调整,从后向前遍历 result
先找 10,设10在 Arr 索引为index,对应 p 里前一个元素(p[index])时 7 ,将 result10 的前一个元素3 改为 7,

再看 7,对应 p 中保存的前一个元素 p[1]2,则将 result 第一个元素改为 2.

找最大递增子序列索引【完整代码】

/*
[3,1,5,4,2] => [1,2]
*/
function lis(arr) {const p = arr.slice();const result = [0]; // 索引数组let i;let j;let u;let v;let c;const len = arr.length;for (i = 0; i < len; i++) {const arrI = arr[i];if (arrI !== 0) {// 取最后一个元素j = result[result.length - 1];if (arr[j] < arrI) {p[i] = j;result.push(i);continue;}u = 0;v = result.length - 1;//result长度大于1时while (u < v) {// 取中位数c = ((u + v) / 2) | 0;if (arr[result[c]] < arrI) {u = c + 1;} else {v = c; //result中位数大于等于 当前项。v取中位数}}if (arrI < arr[result[u]]) {if (u > 0) {p[i] = result[u - 1];}result[u] = i;}}}u = result.length;v = result[u - 1];while (u-- > 0) {result[u] = v;v = p[v];}return result;
}

找最大递增子序列(含项和索引,这是我的小改版)【完整代码】

function lisItem(arr){let p = arr.slice();let result = [{ele: arr[0], idx: 0}];let j;let i;// c, u, v 是保存 result 中 的中位数、确定中位数的起始位置、确定职位数的结束位置。let u;let c;let v;const len = arr.length;for(i =0; i< len; i++){const current = arr[i];if(current !== 0) {j = result.length - 1;if(result[j].ele < current) {console.log(' > : ', i, current);result.push({ele: current, idx: i})p[i] = result[j].idx;}else {u = 0;v = result.length - 1;while(u < v) {c = (u + v) >> 1; // (prev+last)/2 | 0;if(current > result[c].ele){u = c + 1;}else {v = c;}}debugger;// 上面的while主要找出 大于等于当前项的索引值 uconsole.log('修改: ',JSON.stringify(result), u, i, current);if(current < result[u].ele) { // 不断的修正resultif(u>0) {const indexOfArr =  arr.indexOf(result[u-1].ele) // 大于等于当前项的前一项的索引indexOfArr !== -1 && (p[i] = indexOfArr)}result[u] = {ele: current, idx: i}}}}}u = result.length;v = result[result.length - 1];while(--u > 0){result[u] = { ele: arr[v.idx], idx: v.idx };v = { ele: arr[p[v.idx]], idx: p[v.idx] }}return result;}

这篇文章也说的比较清晰,推荐一看 Vue3 DOM Diff 核心算法解析


其它的实现方法

来自 vue-design

const seq = [0, 8, 4, 12, 2, 10]function lis(seq) {const valueToMax = {}let len = seq.lengthfor (let i = 0; i < len; i++) {valueToMax[seq[i]] = 1}let i = len - 1let last = seq[i]let prev = seq[i - 1]while (typeof prev !== 'undefined') {let j = iwhile (j < len) {last = seq[j]if (prev < last) {const currentMax = valueToMax[last] + 1valueToMax[prev] =valueToMax[prev] !== 1? valueToMax[prev] > currentMax? valueToMax[prev]: currentMax: currentMax}j++}i--last = seq[i]prev = seq[i - 1]}const lis = []i = 1while (--len >= 0) {const n = seq[len]if (valueToMax[n] === i) {i++lis.unshift(len)}}return lis
}

最长连续递增子序列, 来自使用JS找出数组中的最长递增子串

 function findL(arr){let arr_act=[];let arr_pre=[];let arr_max=[];for(var i=0;i<arr.length;i++){let val=arr[i]if(arr_act.length==0){arr_act.push(val)}else if(val<arr_act[arr_act.length-1]){arr_pre=arr_act;arr_act=[];arr_act.push(val)}else {arr_act.push(val)}if(arr_pre.length>arr_max.length){arr_max=arr_pre;}}return arr_max.length>arr_act.length?arr_max:arr_act}

最长递增子序列, 来自使用JS找出数组中的最长递增子串

function lis(arr){let arr_max=[];let cache=[];for(var i=0;i<arr.length;i++){cache.push([])}for(let i=0;i<arr.length;i++){for(let j=0;j<i;j++){if(arr[j]<arr[i]){if(cache[i].length<cache[j].length+1){cache[i]=[].concat(cache[j])}}}cache[i].push(arr[i]);if(cache[i].length>arr_max.length){arr_max=[].concat(cache[i])}}return arr_max
}

总结

基本核心要点就是比对当前项与上一项的大小,保存响应的状态最后做更新。
我说的那种方法有什么亮点呢,主要是这里

while (u < v) {// 取中位数c = ((u + v) / 2) | 0;if (arr[result[c]] < arrI) {u = c + 1;} else {v = c; //result中位数大于等于 当前项。v取中位数}
}
if (arrI < arr[result[u]]) {if (u > 0) {p[i] = result[u - 1];}result[u] = i;
}
  • 与中位比大小能省去遍历项,数据量越大效果越明显。
  • 用的变量非常少,思路非常凝练。值得学习的方式。

参考

【个人博客】vue-design
【CSDN】使用JS找出数组中的最长递增子串

寻找数组最大递增子序列相关推荐

  1. 【树状数组】递增子序列(金牌导航 数据结构优化DP-1)

    递增子序列 金牌导航 数据结构优化DP-1 题目大意 给出一个序列,让你求长度为m的单调递增子序列的个数 输入样例 3 2 1 1 2 7 3 1 7 3 5 9 4 8 输出样例 2 12 数据范围 ...

  2. 耐心排序之最长递增子序列(LIS)

    目录 一.问题引入 1.最长递增子序列(LIS) 2.问题分析 3.代码实现 4.问题思考 二.耐心排序 1.基本介绍 2.操作步骤 3.代码实现 三.俄罗斯套娃信封问题 1.题目描述 2.问题分析 ...

  3. 491. Increasing Subsequences 递增子序列

    给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2. 示例: 输入: [4, 6, 7, 7] 输出: [[4, 6], [4, 7], [4, 6, 7], [4, ...

  4. leetcode 491. 递增子序列 思考分析

    题目 给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2. 说明: 给定数组的长度不会超过15. 数组中的整数范围是 [-100,100]. 给定数组中可能包含重复数字 ...

  5. leetcode491. 递增子序列(回溯算法)

    给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2. 示例: 输入: [4, 6, 7, 7] 输出: [[4, 6], [4, 7], [4, 6, 7], [4, ...

  6. LeetCode 491. 递增子序列(回溯+判重剪枝)

    1. 题目 给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2. 示例: 输入: [4, 6, 7, 7] 输出: [[4, 6], [4, 7], [4, 6, 7] ...

  7. Java实现 LeetCode 491递增子序列

    491. 递增子序列 给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2. 示例: 输入: [4, 6, 7, 7] 输出: [[4, 6], [4, 7], [4, ...

  8. 数组字符串那些经典算法:最大子序列和,最长递增子序列,最长公共子串,最长公共子序列,字符串编辑距离,最长不重复子串,最长回文子串 (转)...

    作者:寒小阳 时间:2013年9月. 出处:http://blog.csdn.net/han_xiaoyang/article/details/11969497. 声明:版权所有,转载请注明出处,谢谢 ...

  9. 求数组中最长递增子序列

    写一个时间复杂度尽可能低的程序,求一个一维数组(N个元素)中最长递增子序列的长度. 例如: arr[] = {1, -1, 2, -3, 4, -5, 6, -7},其最长递增子序列的长度为4 如(1 ...

最新文章

  1. JAVA方法中的参数用final来修饰的效果
  2. 使用etcd+confd管理nginx配置
  3. 云南计算机专升本数据结构_怎么查找云南省2019年专升本计算机专业试题
  4. css盒子模型圆形运用,【前端】CSS3学习笔记(三)——盒子模型
  5. fluent design_Fluent Design单选按钮,复选框,选择框,Java菜单
  6. Peacock:大规模主题模型及其在腾讯业务中的应用-2015
  7. 普通人为什么要学习Python
  8. 算法真的太重要了!CSDN用动画帮你快速 get 核心原理
  9. HDU 1018 Big Number
  10. Vitamin-R for Mac(GTD工作效率管理工具)
  11. n分频器 verilog_verilog 语言实现任意分频
  12. 漫话:如何给女朋友解释灭霸的指响并不是真随机消灭半数宇宙人口的?
  13. Navicat 设置自动插入时间触发器
  14. RabbitMQ 实战教程
  15. ios 代码例子 卷边的翻书效果
  16. keras实现deblurgan-v1(图像去模糊)
  17. Network Battery for mac(实时网速显示和电池健康) 教程
  18. 心流状态---人们做事时内心的一种状态
  19. 用 C学习51单片机——记录 4、中断系统 (1)外部中断
  20. dmz和端口映射_使用DMZ主机功能代替FTP服务端口映射无法使用的问题

热门文章

  1. 用超级弹弓把飞船射上月球
  2. 股票数据接口可以获取股价复权数据吗?
  3. JavaScript 问题汇总(一)
  4. 计算机网络复习相关知识点宝典 课后习题答案
  5. 唱吧新品小巨蛋麦克风正式发售 开创无线双人合唱功能
  6. 我的硬汉观——《丧钟为谁而鸣》读书感悟
  7. ffftp搜索服务器上文件,FFFtp的教程
  8. 一个成功的程序员的感悟——激励自己!
  9. 如何一句话让程序员高潮?
  10. html复习第二课(2_34_0910_html)