前言
我们乱序比对的时候,会将节点全部的移动一遍,而我们希望尽可能少的移动,我们只需要找联系最长的,只需要动不连续的,这就是最长递增子序列
第一步
求最长递增子序列,vue3采用的算法是贪心+二分查找
- 在查找中如果当前的比最后的一个大,直接插入
- 如果当前这个比最后一个小,采用二分查找的方式,找到已经排好的列表,找到比当前数大的那一项,将其替换掉
- 先拿到总个数
- 弄一个结果集,放的是索引
- 然后循环,拿出每一项,看看是否等于0,因为0有特殊含义,表示没有patch过,直接插入,前面博文有说到
- 如果不等于0,取出结果集最后一项最后一项,然后拿着最后一项的下标去数组里找对应的值
- 如果这个值小于当前循环中的值,就把当前下标也就是i放入结果集。
- 前面的步骤总结就是,循环数组中的每一项,如果该项不等于0,就拿结果集最后一项所对应的数组中的值与当前项进行比对,如果结果集最后一项所对应的数组中的值比当前项小,就把当前项的索引放入到结果集的末尾
- 如果这个值所对应的数组中的项大于当前循环中的值,则进行二分查找,找到比当前值大的那一个
- 确定开始和结尾,只要开始值和结尾不重合,我们就一直找,如果重合,就说明找到了对应的值
- 首位相加除2或上0,就是本次取的中间值位置的前一个,拿到前一个的值和当前循环的项相比
- 取结果集中的middle项,然后拿这个取出的值去数组里查找对象的值与当前循环的值做对比
- 如果比当前循环的值小,就让start等于当前middle的下一项
- 否则就让end等于middle
- 上述操作就是找到结果集中,比当前这一项大的数
- start或者end 就是最后找到的值,此时start和end
- 然后我们判断当前循环到的值是不是当前的当前查找到的值小,如果小就替换掉,相等或者大就不用换了
第二步
此时我们求的结果其实是不对的,和最终想要的值有一些差异,我们怎么能求到我们想要的值呢?
我们在每次往结果集里放的时候,默认每次放入的时候,我们都要知道,最小的结尾数,所以只要放入的时候,前边有值,那本次放入时,最小结尾数就存在,否则没有。
- 2的前面没人,所以它对应的最小尾数没有
- 放3的时候,2是最小尾数,放1的时候,1比2更有潜力,替换掉2,替换后,1前面也没值,所以就没有最小尾数,以此类推。记得都是放入之前的位置
代码中
- 设置一个变量专门存放索引
- 追加时,p[i] = resultLastIndex 自己当前的下标对应的结果集最后一项的值,也就是前一项
- 替换时,进行判断,如果当前的start>0,才进行记录,因为第一个前面没有元素,不用记录
- 将他要替换的前一个记住
- 最终倒序查找,通过循环,根据前驱节点一个个向前查找
- 求出连续后,就知道哪些不用动了,求出来的是原数组中最长连续子序列的下标
总结一下上述逻辑
- 比它大就往结果集里放
- 如果当前值比结果集最后一项小,就用二分查找,找到比它大的那一项,替换掉它,此时,它比找到的那一项更有潜力,目的就是为了更有潜力,接着去找最长的递增子序列
- 换掉它会导致最终的结果出现问题,我就把每一个放进去之前,记住前一个是谁,这样我们就可以通过最后一项,往前追溯,去追溯没有替换前的正确结果
- 最终我们在拿新的内容把原有覆盖掉,就得到了正确结果
第三步
然后我们回到处理中间新增的逻辑地方
- 调用刚才我们写的方法,把中间新增的数组传进去,拿到里面最长递增子序列的索引
- 有了这个序列之后,我们就不都做插入操作了
- 如果当前i跟最长子序列的最后一项一样就不需要动了,直接跳过,取最长子序列的下一项,下标--。一样就插入
- 这样就跳过了不需要移动的元素
如果您觉得有所收获,麻烦动动小手点个攒,谢谢啦~ 预知后事如何,且听下回分解~