LeetCode题目
- 203.移除链表元素
- 206.反转链表
- 160.相交链表
- 707.设计链表
- 24.两两交换链表中的节点
- 19.删除链表的倒数第 N 个结点
- 142.环形链表 II
简介
- 链表题目需要注意的点
- ListNode结构体要会背
struct ListNode { int val; ListNode* next; ListNode(int _val = 0, ListNode* _next = nullptr) : val(_val) , next(_next) { } }; // 结尾记得加分号
- 先判断head节点是否为nullptr,再进入下一步
- 有效性判断:要对cur取next,就要先判断cur是否为nullptr,再取next
- 善用dummy哨兵节点和pre指针
- 使用pre,cur,next,next2指代已有节点,使用temp指代新建节点
- 一轮处理完后,更新指针
- 基本处理模板
if (!head) return head; ListNode dummy = ListNode(-1, head); ListNode *pre = &dummy, *cur = head, *next; while (cur) { next = cur->next; ... pre = cur; cur = next; } return dummy.next;
- 链表题目常用方法与概念
- 快慢指针,注意有效性判断
while (slow && fast && fast->next) { slow = slow->next; fast = fast->next->next; ... }
- 对撞指针
- 相交链表,尾部对齐,再逐个检查尾部指针,相同处为相交处
- 设计链表时,不要单独实现头插和尾插,统一用指定下标插入实现
- 循环链表,快指针与慢指针重合处,必定为head
- 有环链表,在快慢指针重合处、head,同时出发,重合点为环的起点
题目讲解
- 以综合题707和易错题24、142为例
class MyLinkedList { private: struct ListNode { int val; ListNode* next; ListNode(int _val = 0, ListNode* _next = nullptr) : val(_val) , next(_next) { } }; ListNode* dummy; int64_t size; public: MyLinkedList() : dummy(new ListNode(-1, nullptr)) , size(0) { } int get(int index) { if (index > (size - 1) || index < 0) return -1; ListNode *pre = dummy, *cur = dummy->next, *next; auto cur_index = index - index; while (cur) { next = cur->next; if (cur_index == index) { return cur->val; } ++cur_index; pre = cur; cur = next; } return -1; } // 不要单独实现头插和尾插,统一用指定下标插入实现 void addAtHead(int val) { return addAtIndex(0, val); } void addAtTail(int val) { return addAtIndex(size, val); } void addAtIndex(int index, int val) { if (index > size || index < 0) return; if (0 == size) { dummy->next = new ListNode(val); ++size; return; } ListNode *pre = dummy, *cur = dummy->next, *next; auto cur_index = index - index; while (cur) { next = cur->next; if (cur_index == index) { ListNode* temp = new ListNode(val, cur); pre->next = temp; ++size; break; } ++cur_index; pre = cur; cur = next; } if (index == size) { ListNode* temp = new ListNode(val, cur); pre->next = temp; ++size; } return; } void deleteAtIndex(int index) { if (index > (size - 1) || index < 0) return; ListNode *pre = dummy, *cur = dummy->next, *next; auto cur_index = index - index; while (cur) { next = cur->next; if (cur_index == index) { pre->next = next; delete cur; --size; break; } ++cur_index; pre = cur; cur = next; } return; } };
class Solution { public: ListNode* swapPairs(ListNode* head) { if (!head) return head; if (!(head->next)) return head; ListNode dummy = ListNode(-1, head); ListNode *pre = &dummy, *cur = head, *next, *next2; while (cur && cur->next) { next = cur->next; next2 = next->next; pre->next = next; next->next = cur; cur->next = next2; // 易错点:pre要先更新,并且cur=next2 pre = cur; cur = next2; } return dummy.next; } };
class Solution { public: ListNode* detectCycle(ListNode* head) { if (!head) return NULL; if (!(head->next)) return NULL; ListNode dummy = ListNode(-1, head); ListNode *slow = head, *fast = head; // 易错点:快慢指针有效性判断 while (slow && fast && fast->next) { slow = slow->next; fast = fast->next->next; if (slow == fast) { while (slow != head) { slow = slow->next; head = head->next; } return slow; } } return NULL; } };