移除链表元素 && 设计链表
学会设置虚拟头结点
翻转链表
leetcode 206 https://leetcode.cn/problems/reverse-linked-list/description/
方法一:非递归+新开链表
头插法:创建一个新的链表,遍历旧链表,按顺序在新链表使用头插法分别插入元素。
方法二:非递归+不新开链表+从链表头到链表尾翻转
需要用临时变量temp记录下一个需要操作的节点,左边那个尾pre,右边那个是cur,到了cur是nullptr的时候结束。
class Solution {
public:ListNode* reverseList(ListNode* head) {ListNode* temp;ListNode* cur = head;ListNode* pre = nullptr;while (cur) {temp = cur->next;cur->next = pre;pre = cur;cur = temp;}return pre;}
};
方法三:递归+不新开链表+从链表头到链表尾翻转
递归的过程实际上代替了方法二的pre = cur, cur = temp,其他都没有区别。
class Solution {
public:ListNode* reverse(ListNode* pre, ListNode* cur) {if (cur == nullptr) {return pre;}ListNode* temp;temp = cur->next;cur->next = pre;return reverse(cur, temp);}ListNode* reverseList(ListNode* head) {return reverse(nullptr, head);}
};
方法四:递归+不新开链表+从链表尾到链表头翻转
最后last取到了尾部元素,然后head这个时候是是到倒数第二个元素,倒转指向然后接下来last就等于head,然后head等于last前面那个元素,以此类推直到最后。
class Solution {
public:ListNode* reverseList(ListNode* head) {if (head == nullptr) {return head;}if (head->next == nullptr){return head;}ListNode* last = reverseList(head->next);head->next->next = head;head->next = nullptr;return last;}
};
两两交换链表中的节点
leetcode 24 https://leetcode.cn/problems/swap-nodes-in-pairs/description/
每次cur是需要操作的两个节点的其中一个节点。cur->next->next不可以等于null,否则为奇数个节点,停止循环。每次记录下cur->next和cur->next->next->next。操作顺序及其步骤如下
class Solution {
public:ListNode* swapPairs(ListNode* head) {if (head == nullptr || head->next == nullptr) {return head;}ListNode* dummyhead = new ListNode();dummyhead->next = head;ListNode* cur = dummyhead;while (cur->next != nullptr && cur->next->next != nullptr) {ListNode* first = cur->next;ListNode* third = cur->next->next->next;cur->next = cur->next->next;cur->next->next = first;first->next = third;cur = cur->next->next;}ListNode* result = dummyhead->next;delete dummyhead;return result;}
};
删除链表的倒数第N个节点
使用快慢指针,快指针先走n步,然后快慢指针同时走,直到快指针下一个是null,在慢指针这个位置slow->next = slow->next->next。
链表相交
首先求出两个链表的长度,求出二者之差为n,把长的链表头指针移动n步,然后两个头指针同时移动,相等的时候中断返回。
环形链表II
leetcode 142 https://leetcode.cn/problems/linked-list-cycle-ii/
这里主要涉及公式!
两个要点
- 是否有环:此时因为快慢指针如果有环必定在环里面相遇,就看它们是否在快指针=nullptr之前相遇即可。
- 环形入口:快慢指针在一个点,此时取快指针(慢指针也可以),然后头部一个指针同时移动,两个指针移动速度均为一步一个节点。两个节点相等之处就是环形入口。
class Solution {
public:ListNode *detectCycle(ListNode *head) {ListNode* fast = head;ListNode* slow = head;while (fast && fast->next) {fast = fast->next->next;slow = slow->next;if (fast == slow) {ListNode* result = head;while (result != fast) {result = result->next;fast = fast->next;} return result;}}return nullptr;}
};