学习总结录 学习总结录
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
  • 设计模式

  • 算法思想

    • 前缀和数组
    • 差分数组
    • 原地修改数组
    • 二分搜索
    • 动态规划
    • 回溯算法套路
    • BFS算法套路
    • 双指针技巧套路-链表
      • 双指针技巧套路
      • 快慢指针
        • 环形链表
        • 环形链表II
        • 链表的中间节点
        • 链表中倒数第k个节点
        • 合并两个有序链表
        • 相交链表
      • 参考
    • 双指针技巧套路-数组
    • 滑动窗口
  • 编码规范

  • 技术思想
  • 算法思想
旭日
2023-03-27
目录

双指针技巧套路-链表

# 双指针技巧套路

双指针一般有两种类型快慢指针和左右指针。快慢指针一般用于链表或者数组中需要删除、移动等情况。左右指针一般用于数组查询等情况。

# 快慢指针

题目:

141. 环形链表 (opens new window)

142. 环形链表 II (opens new window)

876. 链表的中间结点 (opens new window)

剑指 Offer 22. 链表中倒数第k个节点 (opens new window)

21. 合并两个有序链表 (opens new window)

160. 相交链表 (opens new window)

# 环形链表

题目:

image-20220313153430900

思想:

定义两个快慢指针,快指针做一定限制,然后快指针和慢指针依次往后走, 快指针依次往后走两个,如果当快指针遇到慢指针(相当于跑步超了一圈),这时候就说明有环。

代码:

public class Solution {
    public boolean hasCycle(ListNode head) {
        ListNode fast, slow;
        fast = slow = head;
        while(fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow) {
                return true;
            }
        }
        return false;
    }
}

# 环形链表II

题目:

image-20220313161600522

思想:

可以把这题想成一个一部分是直线跑道,另一部分是环形跑道,一旦进入环形跑道就一直在环形跑道跑步的情况。那么现在有A和B节点,B跑得比较快,A和B会在环形跑道相遇。

设A这时候跑步的距离为k,那么B这时候的跑步距离一定是2k。设A在环形跑道跑了m距离,那么直线跑道的距离为

k-m。那么可以算出B在环形跑道跑路的距离为2k-(k-m)=k+m。而B能够在环形跑道和A第一次相遇,说明B在环形跑道跑路的距离是比A跑步的距离多了一圈,故我们能算出一圈的距离为:k

此刻我们发现从相遇点到环形跑步的起点的距离为:k-m,而从直线跑道起点到环形跑道起点的距离也为:k-m。

代码:

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast, slow;
        fast = slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) break;
        }
        // 上面的代码类似 hasCycle 函数
        if (fast == null || fast.next == null) {
            // fast 遇到空指针说明没有环
            return null;
        }

        // 重新指向头结点
        slow = head;
        // 快慢指针同步前进,相交点就是环起点
        while (slow != fast) {
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

# 链表的中间节点

题目:

image-20220313165316693

思想:

快慢指针依次遍历链表,当快指针到达链表结尾,返回慢指针的位置。

代码:

public class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode fast, slow;
        fast = slow = head;
        while(fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }
}

# 链表中倒数第k个节点

题目:

image-20220313170432132

思想:

先让快指针移动k次,然后快慢一起向后移动,快指针到达链表末尾的时候,返回慢指针即可。

代码:

class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
        ListNode fast, slow;
        fast = slow = head;
        for(int i = 0; i < k; i++) {
            fast = fast.next;
        }
        while(fast != null) {
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

# 合并两个有序链表

题目:

image-20220316093115354

思想:

运用头指针的技巧,然后用两个指针分别遍历两个链表,较小节点加入链表即可。

代码:

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
    
        // 头结点
        ListNode head = new ListNode(-1), p = head;
        ListNode p1 = list1, p2 = list2;
        
        while (p1 != null && p2 != null) {
            // 比较 p1 和 p2 两个指针
            // 将值较小的的节点接到 p 指针
            if (p1.val > p2.val) {
                p.next = p2;
                p2 = p2.next;
            } else {
                p.next = p1;
                p1 = p1.next;
            }
            // p 指针不断前进
            p = p.next;
        }
        
        if (p1 != null) {
            p.next = p1;
        }
        
        if (p2 != null) {
            p.next = p2;
        }
        return head.next;
    }
}

# 相交链表

题目:

image-20220316103423502

思想:

这道题类似与环形链表,两个链表所走路的不同是因为他们在相交节点前所走的路不同,所以只要让两个链表节点,先走完自己的路,然后再走对方在相交节点之前的路就可以保证两者同时达到同一节点。

代码:

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode p = headA;
        ListNode q = headB;
        while(p != q) {
            if(p == null) {
                p = headB;
            } else {
                p = p.next;
            }
            if(q == null) {
                q = headA;
            } else {
                q = q.next;
            }
        }
        return q;
    }
}

# 参考

双指针技巧秒杀七道链表题目

上次更新: 2024/06/29, 15:13:44
BFS算法套路
双指针技巧套路-数组

← BFS算法套路 双指针技巧套路-数组→

最近更新
01
基础概念
10-31
02
Pytorch
10-30
03
Numpy
10-30
更多文章>
Theme by Vdoing | Copyright © 2021-2024 旭日 | 蜀ICP备2021000788号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式