• [饭后算法系列] "头尾移动" 排序列表


    1. 问题

    一个乱序列表(list), 只支持两种操作: 把一个元素移动到头部, 或者把一个元素移动到尾部. 需要设计一种算法, 使得移动次数最少而使列表有序

    举两个例子:

    1. {3,5,7,1,9,10,8}. 最少需要移动3次: 1移动到头部, 9移动到尾部, 10移动到尾部

    2. {6,5,4,3,2,1}. 最少需要移动5次: 将2,3,4,5,6依次移动到尾部, 或者将5,4,3,2,1依次移动到头部

    2. 分析

    这题和其他算法不一样的地方在于求严格的最优移动次数, 而不是移动次数的复杂度, 也不要求整体算法的复杂度, 因此只要考虑怎么最小化移动次数即可

    3. 暴力法

    暴力法是算法的一个标杆, 表明了"最差"的算法需要移动多少次, 这可以给我们思考最优算法提供一个直观的界线

    拿这道题目来说, 用暴力法怎么解用例1中的{3,5,7,1,9,10,8}?

    我们可以无视任何优化, 简单地把列表中最小的数字(1)移动到尾部, 再将次小的数字(3)移动到尾部, 这样依次将5,7,8,9,10移动到尾部, 就完成了整个列表的排序, 总共需要移动n次, n为列表的元素个数.

    也就是说, 对于一个最优算法, 移动次数一定是小于n的

    4. 算法优化

    4.1 标准化

    根据暴力法我们可以发现, 我们需要知道每个数字在列表中的大小关系, 也就是需要知道1是最小的, 3是次小的

    所以我们需要把列表标准化, 标准化后的列表元素, 是原列表元素从小到大的序号. 即3在原数组中第2大, 所以3标准化为2. 以此类推, 用例1标准化为: {2,3,4,1,6,7,5}

    下面所有的操作都针对标准化后的列表

    4.2 算法主体

    1. 找到列表中最长的 '步进1递增子序列', 比如用例一中的2,3,4,5. 注意这里一定要步进为1, 所以虽然2,3,4,6,7是最长的递增子序列, 但是4->6的步进不为1, 所以不考虑

    2. 假设找到的最长步进1递增子序列为 i, i+1, ..., j, (长度为k) 那么剩下的工作就是把其他元素归位:

    2.1 依次把 i-1, i-2, ..., 1移动到头部

    2.2 依次把 j+1, j+2, ..., n移动到尾部

    总共的移动次数为 n-k

    关键字: 算法, 排序, 列表

  • 相关阅读:
    HTTP 错误 403.6
    NPOI-WebForm_Excel导入与导出
    一触即发 App启动优化最佳实践
    如何查看手机是硬件加密还是软件加密
    Android EidtText 光标的使用和设置
    jd-gui报错INTERNAL ERROR 解决办法
    你应该知道的那些Android小经验
    如何分析解决Android ANR
    Android延时执行调用的几种方法
    转:各种Adapter的用法
  • 原文地址:https://www.cnblogs.com/testview/p/3617966.html
Copyright © 2020-2023  润新知