• 链表


    单链表

    尾结点指针指向一个空地址NULL,表示这是链表上的最后一个结点。

    循环链表

    尾结点指针是指向链表的头结点。
    约瑟夫问题

    双向链表

    每个结点不止有一个后继指针 next 指向后面的结点,还有一个前驱指针 prev 指向前面的结点。
    双向链表要比单链表占用更多的内存空间
    Java 语言的 LinkedHashMap 容器
    用空间换时间的设计思想

    查找

    因为链表中的数据并非连续存储的,所以无法像数组那样,根据首地址和下标,通过寻址公式就能直接计算出对应的内存地址,而是需要根据指针一个结点一个结点地依次遍历,直到找到相应的结点。
    需要 O(n) 的时间复杂度。

    插入和删除操作

    针对链表的插入和删除操作,只需要考虑相邻结点的指针改变,所以对应的时间复杂度是 O(1)。
    删除某个结点 q 需要知道其前驱结点,单链表删除操作需要 O(n) 的时间复杂度,而双向链表只需要 O(1) 的时间复杂度。

    链表 VS 数组

    对链表进行频繁的插入、删除操作,还会导致频繁的内存申请和释放,容易造成内存碎片,如果是 Java 语言,就有可能会导致频繁的 GC(Garbage Collection,垃圾回收)

    基于链表实现 LRU 缓存淘汰算法

    思路:维护一个有序单链表,越靠近链表尾部的结点是越早之前访问的。当有一个新的数据被访问时,我们从链表头开始顺序遍历链表。

    1. 如果此数据之前已经被缓存在链表中了,我们遍历得到这个数据对应的结点,并将其从原来的位置删除,然后再插入到链表的头部。
    2. 如果此数据没有在缓存链表中,又可以分为两种情况:如果此时缓存未满,则将此结点直接插入到链表的头部;如果此时缓存已满,则链表尾结点删除,将新的数据结点插入链表的头部。

    缓存访问的时间复杂度:不管缓存有没有满,都需要遍历一遍链表,所以这种基于链表的实现思路,缓存访问的时间复杂度为 O(n)。

    优化1:引入散列表(Hash table)来记录每个数据的位置,将缓存访问的时间复杂度降到 O(1)。
    优化2:用数组来实现 LRU 缓存淘汰策略

    判断一个字符串是否是回文字符串的问题

    思路1:
    1.对字符串s进行遍历,保留其中的字母和数字字符,放到另一个字符串sgood中;
    2.使用字符串翻转API得到sgood的逆序字符串sgood_rev;
    3.对比sgood和sgood_rev,只要字符串相同,sgood就是回文串。

    思路2:
    双指针,左右指针分别指向 sgood 的两侧

    以上:时间复杂度O(n),空间复杂度O(n)

    思路3:在原字符串上直接判断,使用双指针
    时间复杂度O(n),空间复杂度O(1)

  • 相关阅读:
    SonarQube 之 权限模板配置
    window jenkins + sonarqube + sonar-scanner 最佳实践
    到某个指定的页面不可以后退
    php里面判断是pc还是手机
    爱奇艺视频引入
    给电脑安装字体
    应用宝下线
    ps 如何的复制想要的东西,以及修改
    实现倒计时的效果(3秒倒计时)
    数据库里的数据被删除,依然想按照顺序往下递增的解决办法
  • 原文地址:https://www.cnblogs.com/samniu/p/14547112.html
Copyright © 2020-2023  润新知