算法通关村第一关-双指针专题:寻找中间节点、寻找倒数第K个节点、旋转链表

双指针
  • 定义快慢指针(slow、fast)
寻找中间节点
  • 快慢指针均指向头节点
  • 快指针一次跳俩步,慢指针一次跳一步,两指针同时移动
  • 当快指针指向节点为空(偶数个节点)或快指针指向节点的后继节点为空(奇数个节点)时,两指针停止移动
  • 此时,慢指针指向链表中间节点

image-20230722225346291

  • 具体代码如下:
/**
     * 寻找中间节点
     * @param head
     * @return
     */
    public static ListNode middleNode(ListNode head) {
        // 1.快慢指针
        ListNode slow = head, fast = head;
        // 2.快指针指向尾节点
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        // 3.返回中间节点
        return slow;
    }
寻找倒数第K个节点
  • 快慢指针均指向头节点
  • 快指针跳到第K+1个节点,此时慢指针与快指针相距K个节点
  • 快慢指针同时移动,当快指针指向链表末端(即空节点)时,两指针停止移动
  • 此时,慢指针指向链表的倒数第K个节点

image-20230722225332136

  • 具体代码如下:
/**
     * 寻找倒数第K个节点
     * @param head
     * @param k
     * @return
     */
    public static ListNode getKthFromEnd(ListNode head, int k) {
        // 1.快慢指针
        ListNode fast = head;
        ListNode slow = head;
        // 2.快指针指向 K+1
        while (fast != null && k > 0) {
            fast = fast.next;
            k--;
        }
        // 3.快指针指向链表末
        while (fast != null) {
            fast = fast.next;
            slow = slow.next;
        }
        // 4.返回倒数第K节点
        return slow;
    }
旋转链表
  • 常见的情景题:把链表的每个节点,都向右移动K个位置
  • 这个是有两种思路的:反转链表、转化为寻找倒数第 K-1 个节点
  • 反转链表暂且不表,这里可以看看第二种方法:转化为寻找倒数第 K-1 个节点
  • 把链表的每个节点,都向右移动K个位置 => 把链表的后 K 个节点,都旋转成前 K 个节点
  • 那就把问题转换成了:转化为寻找倒数第 K-1 个节点:
  • 此时慢指针指向了倒数第 K-1 个节点,快指针指向了链表的尾节点
  • 倒数第 K 个节点为头节点(断掉慢指针指向节点的后继,快指针指向原头节点)

image-20230722225315216

  • 具体代码如下:
 /**
     * 旋转链表
     *
     * @param head
     * @param k
     * @return
     */
    public static ListNode rotateRight(ListNode head, int k) {
        if (head == null || k == 0) {
            return head;
        }
        // 1.快慢节点
        ListNode temp = head;
        ListNode fast = head;
        ListNode slow = head;
        // 2.获取链表长度
        int len = 0;
        while (head != null) {
            head = head.next;
            len++;
        }
        // 3.以首尾旋转
        if (k % len == 0) {
            return temp;
        }
        // 4.快指针先走K步
        while ((k % len) > 0) {
            k--;
            fast = fast.next;
        }
        // 5.快慢指针同时走
        while (fast.next != null) {
            fast = fast.next;
            slow = slow.next;
        }
        // 6.获得截断处
        ListNode res = slow.next;
        slow.next = null;
        // 7.重置头节点
        fast.next = temp;
        return res;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值