链表倒数第k个节点

105 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 14 天,点击查看活动详情

Day42 2023/02/17

难度:简单

题目

image.png

思路


本题可以采用双指针的方式,即一快一慢两个指针,我们知道从倒数第k个节点(包括自身)出发一直到最后一个节点一共有k个节点(包括最后一个节点),所以如果有两个指针,一开始就相差k个节点,呢么当两个指针同时移动,其中一个指针指向最后一个节点时,这时另一个指针就指向目标节点了。
具体步骤:

  1. 一开始上fast指针向行k步。
  2. 然后fast和slow指针同时出发,当fast指向表尾指针的下一个节点,slow指针就指向了目标节点。
  3. 返回目标节点的值。

关键点


  • 这里fast指针最后没有指向尾节点,而是在向后走了一个步,是为了slow指针在多走一步正好指向目标节点,不然就指向了前驱节点。但如果题目要求是删除倒数第k个节点的话就可以这样方便找到前驱节点进行删除操作。

算法实现


c++代码实现-双指针法

#include <iostream>
using namespace std;

//定义单链表
struct LNode {
  int val;
  LNode *next;
  LNode(int x) : val(x), next(nullptr){};
};

//返回链表倒数第K个节点
int FindKToTail(LNode *head, int k) {
  LNode *fast = head,
        *slow = head; //快慢指针一开始都指向逻辑上的头节点
  //先让fast指针先走k步
  while (k--) {
    if (!fast)
      break; // k值非法输入(k > n)
    fast = fast->next;
  }
  // fast,slow指针同时出发
  while (fast) {
    fast = fast->next;
    slow = slow->next;
  } //循环结束slow正好指向倒数第k个节点
  return slow->val;
}

int main() {
  //测试以下
  //手动创建一个链表1->2->3
  LNode *head = new LNode(1), *second = new LNode(2), *third = new LNode(3);
  head->next = second;
  second->next = third;
  int res = FindKToTail(head, 1); //返回倒数第三个节点的值,即1
  cout << "结果为:" << res;
  return 0;
}

  • 时间复杂度 O(n)O(n) --- fast和slow一起访问了全部节点,其中n为节点个数
  • 空间复杂度 O(1)O(1) --- 链表为必要空间,无额外辅助空间

总结

碰到数组,链表这一类与之类似的题目,都可以考虑以下双指针的方法