leetcode:19. 删除链表的倒数第 N 个结点

题目

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例:
[中等] 19. 删除链表的倒数第 N 个结点 - 图1

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

解答 & 代码

快慢指针:快指针先走 N 步,然后两个一起走,快指针走到 nullptr 时慢指针恰好走到倒数第 N 个节点。又因为题目是要删除倒数第 N 个节点,所以应该定位到倒数第 N + 1 个节点。快指针走到 fast->next == nullptr 时,慢指针恰好走到倒数第 N + 1 个节点。

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode() : val(0), next(nullptr) {}
  7. * ListNode(int x) : val(x), next(nullptr) {}
  8. * ListNode(int x, ListNode *next) : val(x), next(next) {}
  9. * };
  10. */
  11. class Solution {
  12. public:
  13. ListNode* removeNthFromEnd(ListNode* head, int n) {
  14. ListNode* dummyHead = new ListNode(-1, head); // 虚拟头节点
  15. ListNode* fast = dummyHead; // 快指针
  16. ListNode* slow = dummyHead; // 慢指针
  17. // 快指针先走 n 步
  18. int i = 0;
  19. while(fast != nullptr && i < n)
  20. {
  21. fast = fast->next;
  22. ++i;
  23. }
  24. // 如果 i < n,说明链表长度小于 n,不用删除,直接返回头节点
  25. if(i < n)
  26. return dummyHead->next;
  27. // 快慢指针同时走,最终将 slow 定位到倒数第 N+1 个节点
  28. while(fast->next != nullptr)
  29. {
  30. fast = fast->next;
  31. slow = slow->next;
  32. }
  33. // 删除倒数第 N 个节点
  34. ListNode* deleteNode = slow->next;
  35. slow->next = slow->next->next;
  36. delete deleteNode;
  37. return dummyHead->next;
  38. }
  39. };

复杂度分析:设链表共 M 个节点

  • 时间复杂度 O(M)
  • 空间复杂度 O(1)

执行结果:

  1. 执行结果:通过
  2. 执行用时:4 ms, 在所有 C++ 提交中击败了 77.40% 的用户
  3. 内存消耗:10.3 MB, 在所有 C++ 提交中击败了 93.54% 的用户

换种写法:

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode() : val(0), next(nullptr) {}
  7. * ListNode(int x) : val(x), next(nullptr) {}
  8. * ListNode(int x, ListNode *next) : val(x), next(next) {}
  9. * };
  10. */
  11. class Solution {
  12. private:
  13. // 返回倒数第 n 个节点
  14. ListNode* NthFromEnd(ListNode* head, int n)
  15. {
  16. ListNode* fast = head; // 快指针
  17. ListNode* slow = head; // 慢指针
  18. // 快指针先走 n 步
  19. int i = 0;
  20. for(; i < n && fast != nullptr; ++i)
  21. fast = fast->next;
  22. if(i < n) // 链表长度 < n,不存在倒数第 n 个节点,返回 nullptr
  23. return nullptr;
  24. // 快慢指针同时走
  25. while(fast != nullptr)
  26. {
  27. fast = fast->next;
  28. slow = slow->next;
  29. }
  30. return slow; // 返回倒数第 n 个节点
  31. }
  32. public:
  33. ListNode* removeNthFromEnd(ListNode* head, int n) {
  34. ListNode* dummyHead = new ListNode(-1, head); // 虚拟头节点
  35. // 先定位到倒数第 N+1 个节点
  36. ListNode* lastN1thNode = NthFromEnd(dummyHead, n + 1);
  37. // 删除倒数第 N 个节点
  38. if(lastN1thNode != nullptr)
  39. {
  40. ListNode* deleteNode = lastN1thNode->next;
  41. lastN1thNode->next = lastN1thNode->next->next;
  42. delete deleteNode;
  43. }
  44. return dummyHead->next;
  45. }
  46. };