算法村第一关 白银挑战 | 链表经典问题之双指针专题

所谓的双指针就是定义两个变量,在遍历链表的过程中,移动的步数不同步。在面试中,属于高频问题。

1. 寻找中间结点

876. 链表的中间结点 - 力扣(LeetCode)

1.1 问题描述

给你单链表的头结点 head ,请你找出并返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

1.2 示例

示例 1:

输入:head = [1,2,3,4,5]
输出:[3,4,5]
解释:链表只有一个中间结点,值为 3 。

示例 2:

输入:head = [1,2,3,4,5,6]
输出:[4,5,6]
解释:该链表有两个中间结点,值分别为 3 和 4 ,返回第二个结点。

1.3 代码实现

使用快慢指针,简单直接 快指针fast一次走两步,慢指针slow一次走一步,这样fast到达链表尾部时,slow必然位于中间。

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

1.4 相似题

算法村第一关 白银挑战 | 链表经典问题之双指针专题_第1张图片

2. 寻找倒数第K个元素

面试题 02.02. 返回倒数第 k 个节点 - 力扣(LeetCode)

2.1 问题描述

实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。

2.2 示例

示例:

输入: 1->2->3->4->5 和 k = 2
输出: 4

说明:

给定的 k 保证是有效的。

2.3 代码实现

快指针fast先找到k+1的位置在哪儿,此时slow仍在头结点,两者相差k个结点;此时同步向后移动,当fast到达尾结点时,slow刚好指向倒数第k个结点。本题说明提到,给定的k保证是有效的,但也要警惕,k是大于链表长度的,这样则需要对k做一次取模操作,即 k = k % len

class Solution {
    public int kthToLast(ListNode head, int k) {
        ListNode fast = head;
        ListNode slow = head;
        // fast先去找 k+1 的位置
        while (fast != null && k > 0) {
            fast = fast.next;
            k--;
        }
        // 找到后,同步一起走
        while (fast != null) {
            fast = fast.next;
            slow = slow.next;
        }
        return slow.val;
    }
}

2.4 相似题

算法村第一关 白银挑战 | 链表经典问题之双指针专题_第2张图片

3. 旋转链表

61. 旋转链表 - 力扣(LeetCode)

3.1 问题描述

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

3.2 示例

示例 1:

算法村第一关 白银挑战 | 链表经典问题之双指针专题_第3张图片

输入:head = [1,2,3,4,5], k = 2
输出:[4,5,1,2,3]

示例 2:

算法村第一关 白银挑战 | 链表经典问题之双指针专题_第4张图片

输入:head = [0,1,2], k = 4
输出:[2,0,1]

3.3 代码实现

在倒数第k个位置,链表被分成了链表A  {1,2,3} 和链表B {4,5};那么就可以用题2的思路,找到这个位置,将两个链表调整一下并重新连接。

还可以将链表整体反转* 下一关内容,{5,4,3,2,1},再将前k 和 n-k 两个部分分别反转,即{4,5} 和 {1,2,3}

class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        if (head == null || k == 0) {
            return head;
        }
        ListNode temp = head;
        ListNode fast = head;
        ListNode slow = head;
        int len = 0;
        // 遍历链表,计算长度
        while (head != null) {
            head = head.next;
            len++;
        }
        // 重新计算需要旋转的步数k
        if (k % len == 0){
            return temp;
        }
        while ((k % len) > 0) {
            k--;
            // fast找位置
            fast = fast.next;
        }
        // 同步一起走
        while (fast.next != null) {
            fast = fast.next;
            slow = slow.next;
        }
        ListNode res = slow.next;
        slow.next = null;
        fast.next = temp;
        return res;
    }
}

3.4 相似题

算法村第一关 白银挑战 | 链表经典问题之双指针专题_第5张图片

4. 总结

本文介绍了链表面试题中比较高频的一个系列,双指针专题,通过三道练习题——寻找中间结点、寻找倒数第K个元素、旋转链表,应用快慢双指针fast和slow进行结题。结题关键在于,fast在过程一怎么走,使得过程二双指针同步移动时,fast到达尾结点,刚好返回slow的结点或者值。

你可能感兴趣的:(算法村,算法笔记,算法,链表,数据结构)