2021-09-02 剑指offer22: 链表中倒数第k个节点

·  阅读 95

剑指 Offer 22. 链表中倒数第k个节点

难度简单

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。

例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4`的节点。

示例:

给定一个链表: 1->2->3->4->5, 和 k = 2.

返回链表 4->5.
复制代码

分析

由题可知, 要获取链表中倒数第k个节点, 就得先找到倒数第k个节点,
那么如何找到倒数第k个节点呢,

题解

方法一 直接获取:

最容易想到的就是直接获取

  • 先遍历链表, 获取这个链表的长度n, 那么倒数第k个节点, 按正序的顺序就是第 n-k+1 的节点
  • 再遍历一遍链表, 遍历至 第 n-k+1个节点, 返回即可

这个需要遍历两次链表, 2n, 时间复杂度就是 O(n), 空间复杂度O(1), 因为没有占用其他内存

具体代码:

public ListNode getKthFromEnd(ListNode head, int k) {
  // 直接获取
  ListNode dummyNode = new ListNode(0);
  dummyNode.next = head;
  // 获取链表的长度
  int n = 0;
  while (dummyNode.next != null) {
    n++;
    dummyNode = dummyNode.next;
  }
  dummyNode.next = head;
  // 倒数第k个节点就是正序第 n - k个节点
  int index = n - k + 1;
  while (index != 0) {
    index--;
    dummyNode = dummyNode.next;
  }
  return dummyNode;
}

// Definition for singly-linked list.
public static class ListNode {
  int val;
  ListNode next;

  ListNode(int x) {
    val = x;
  }
}
复制代码
方法二 双指针:

也可以通过双指针来遍历链表

  1. 慢指针指向链表的开始位置, 快指针先跑k步,
  2. 然后快慢指针依次往后遍历
  3. 等到快指针遍历到链表的结尾, 因为快慢指针中间相差了k步, 那么慢指针就是链表中倒数第k个节点, 返回慢指针

具体代码:

public ListNode getKthFromEnd(ListNode head, int k) {
  // 双指针
  // 快慢指针, 快指针先跑k步
  ListNode slowNode = new ListNode(0);
  ListNode fastNode = new ListNode(0);
  slowNode.next = head;
  fastNode.next = head;
  for (int i = 0; i < k; i++) {
    fastNode = fastNode.next;
  }
  // 再往后遍历,快指针为空时,表示到达链表尾部,慢指针就是倒数第k个
  while (fastNode != null) {
    slowNode = slowNode.next;
    fastNode = fastNode.next;
  }
  return slowNode;
}

// Definition for singly-linked list.
public static class ListNode {
  int val;
  ListNode next;

  ListNode(int x) {
    val = x;
  }
}
复制代码
分类:
后端
标签: