今天做了一道链表相关的算法题,观看其他大佬的题解时发现可以用快慢指针解决,于是又做了几道类似的题,索性就写一篇博客总结下来,以后也会经常总结这些相似的算法题。
快慢指针
快慢指针就是存在两个指针,一个快指针,一个慢指针,两个指针每次移动的速度不一样,快的移动的快,慢的移动的慢。快慢指针中的快慢指的是移动的步长,即每次向前移动速度的快慢。例如可以让快指针每次沿链表向前移动2,慢指针每次向前移动1次。
例题总结
1. 链表中倒数第k个节点
1.1 题目详情
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。
例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。
1.2 快慢指针
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
ListNode fastNode = head, slowNode = head;
while(k-- > 0) fastNode = fastNode.next;
while(fastNode != null){
fastNode = fastNode.next;
slowNode = slowNode.next;
}
return slowNode;
}
}
2. 链表的中间结点
2.1 题目详情
给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点
提示:
- 给定链表的结点数介于 1 和 100 之间。
2.2 快慢指针
class Solution {
public ListNode middleNode(ListNode head) {
ListNode fastNode = head, slowNode = head;
while(fastNode != null && fastNode.next !=null){
slowNode = slowNode.next;
fastNode = fastNode.next.next;
}
return slowNode;
}
}
3. 环形链表
3.1 题目详情
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
提示:
- 链表中节点的数目范围是 [0, 104]
- 105 <= Node.val <= 105
- pos 为 -1 或者链表中的一个 有效索引
3.2 快慢指针
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null || head.next == null) return false;
ListNode fastNode = head.next, slowNode = head;
while(fastNode != slowNode){
if(fastNode == null || fastNode.next == null) return false;
slowNode = slowNode.next;
fastNode = fastNode.next.next;
}
return true;
}
}
4. 环形链表||
4.1 题目详情
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改链表。
提示:
- 链表中节点的数目范围在范围 [0, 104] 内
- 105 <= Node.val <= 105
- pos 的值为 -1 或者链表中的一个有效索引
4.2 快慢指针
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fastNode = head, slowNode = head, temp = head;
while(true){
if(fastNode == null || fastNode.next == null) return null;
slowNode = slowNode.next;
fastNode = fastNode.next.next;
if(slowNode == fastNode) break;
}
fastNode = head;
while(fastNode != slowNode){
fastNode = fastNode.next;
slowNode = slowNode.next;
}
return slowNode;
}
}
5. 删除链表的倒数第 N 个结点
5.1 题目详情
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
提示:
- 链表中结点的数目为 sz
- 1 <= sz <= 30
- 0 <= Node.val <= 100
- 1 <= n <= sz
4.2 快慢指针
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyNode = new ListNode(0, head);
ListNode fastNode = head, slowNode = dummyNode;
while(n-- > 0) fastNode = fastNode.next;
while(fastNode != null){
fastNode = fastNode.next;
slowNode = slowNode.next;
}
slowNode.next = slowNode.next.next;
return dummyNode.next;
}
}