链表
标记简介
一个(×)代表看不懂题解。
没有标记代表没有整理。
一个(√)代表能看懂解析和代码,有思路,实现不完全。
两个(√)代表有思路,能自己实现。
三个(√)代表掌握,从思路-》代码实现-》时间、空间复杂度。
四个(√)代表完全掌握,从思路-》代码实现-》时间、空间复杂度-》不同解法-》相似题型。
移除链表元素
203.移除链表元素(√)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
if(head == nullptr) return nullptr;
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* p = dummy;
while(p->next != nullptr)
{
if(p->next->val == val)
{
ListNode* tmp = p->next;
p->next = p->next->next;
delete tmp;
}
else
{
p = p->next;
}
}
return dummy->next;
}
};
237. 删除链表中的节点(√)
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点。传入函数的唯一参数为 要被删除的节点 。
偷梁换柱
class Solution {
public:
void deleteNode(ListNode* node) {
if(node == NULL) { return; }
node->val = node->next->val;
node->next = node->next->next;
}
};
83. 删除排序链表中的重复元素(√)
链接: 83.删除排序链表中的重复元素.
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(head == nullptr) { return nullptr; }
ListNode* node = head;
while(node->next != nullptr)
{
if(node->val == node->next->val)
{
ListNode* temp = node->next;
node->next = temp->next;
delete temp;
}
else
{
node = node->next;
}
}
return head;
}
};
82. 删除排序链表中的重复元素 II
链接: 82.删除排序链表中的重复元素 II.
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(head == nullptr)
{
return nullptr;
}
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* node = dummy;
while(node->next != nullptr && node->next->next != nullptr)
{
if(node->next->val == node->next->next->val)
{
int val_prev = node->next->val;
while(node->next != nullptr && val_prev == node->next->val)
{
ListNode* temp = node->next;
node->next = temp->next;
delete temp;
}
}
else
{
node = node->next;
}
}
return dummy->next;
}
};
- 分隔链表
链接: 83. 分隔链表.
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
if(head == nullptr)
{
return nullptr;
}
ListNode* leftDummy = new ListNode(0);
ListNode* left = leftDummy;
ListNode* rightDummy = new ListNode(0);
ListNode* right = rightDummy;
ListNode* node = head;
while(node != nullptr)
{
if(node->val < x)
{
left->next = node;
left = left->next;
}
else
{
right->next = node;
right = right->next;
}
node = node->next;
}
right->next = nullptr;
left->next = rightDummy->next;
return leftDummy->next;
}
};
追赶指针技巧(双指针/快慢指针)
对于寻找list某个特定位置的问题,不妨⽤两个变量chaser与runner,以不同的速度遍历list,找到⽬标位置: ListNode *chaser = head, *runner = head。
876. 链表的中间结点(√)
链接: 876. 链表的中间结点.
class Solution {
public:
ListNode* middleNode(ListNode* head) {
if(head == nullptr) { return nullptr; }
ListNode* slow = head;
ListNode* fast = head;
while(fast != nullptr && fast->next != nullptr)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
};
剑指 Offer 22. 链表中倒数第k个节点(√)
链接: 链表中倒数第k个节点.
class Solution {
public:
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* fast = dummy;
ListNode* slow = dummy;
while(fast->next && k--)
{
fast = fast->next;
}
while(fast->next != nullptr)
{
fast = fast->next;
slow = slow->next;
}
return slow->next->val;
}
};
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
if(head == nullptr || n < 0) { return nullptr; }
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* fast = dummy;
ListNode* slow = dummy;
while(fast->next && n--)
{
fast = fast->next;
}
while(fast->next != nullptr)
{
fast = fast->next;
slow = slow->next;
}
ListNode* tmp = slow->next;
slow->next = slow->next->next;
delete tmp;
return dummy->next;
}
};
141. 环形链表(√)
链接: 141. 环形链表.
class Solution {
public:
bool hasCycle(ListNode *head) {
if ((head == nullptr) || (head->next == nullptr)) return false;
ListNode *slow = head;
ListNode *fast = head;
do
{
if((fast == nullptr) || (fast->next == nullptr))
{
return false;
}
slow = slow->next;
fast = fast->next->next;
}while(slow != fast);
return true;
}
};
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head == NULL) { return false; }
ListNode* fast = head;
ListNode* slow = head;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if(fast == slow) { return true; }
}
return false;
}
};
142. 环形链表 II / 剑指 Offer II 022. 链表中环的入口节点(√)
链接: 142. 环形链表 II.
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(head == NULL)
{
return NULL;
}
ListNode* slow = head;
ListNode* fast = head;
do{
if((fast == NULL) || (fast->next == NULL))
{
return NULL;
}
slow = slow->next;
fast = fast->next->next;
}while(slow != fast);
ListNode* ptr = head;
while(slow != ptr)
{
ptr = ptr->next;
slow = slow->next;
}
return slow;
}
};
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head == NULL) { return false; }
ListNode* fast = head;
ListNode* slow = head;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if(fast == slow) { return true; }
}
return false;
}
};
160. 相交链表(√)
链接: 160.相交链表.
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA;
ListNode* curB = headB;
int lenA = 0;
int lenB = 0;
while(curA != NULL)
{
lenA++;
curA = curA->next;
}
while(curB != NULL)
{
lenB++;
curB = curB->next;
}
curA = headA;
curB = headB;
if(lenB > lenA)
{
swap(lenA, lenB);
swap(curA, curB);
}
int gap = lenA - lenB;
while(gap--) { curA = curA->next; }
while(curA != NULL)
{
if(curA == curB) { return curA; }
curA = curA->next;
curB = curB->next;
}
return NULL;
}
};
61. 旋转链表(√)
链接: 61. 旋转链表.
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if(head == nullptr || head->next == nullptr || k == 0)
{
return head;
}
int count = 1;
ListNode* p = head;
while(p->next != nullptr)
{
p = p->next;
count++;
}
int offset = count - k % count;
if(offset == count)
{
return head;
}
p->next = head;
while(offset--)
{
p = p->next;
}
ListNode* ret = p->next;
p->next = nullptr;
return ret;
}
};
反转链表
206. 反转链表(√)
链接: 206. 反转链表.
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* pre = nullptr;
ListNode* cur = head;
ListNode* tmp;
while (cur) {
tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
};
92. 反转链表 II(√)
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
// 设置 dummyNode 是这一类问题的一般做法
ListNode *dummy = new ListNode(0);
dummy->next = head;
ListNode *pre = dummy;
for (int i = 0; i < left - 1; i++) {
pre = pre->next;
}
ListNode *cur = pre->next;
ListNode *tmp;
for (int i = 0; i < right - left; i++) {
tmp = cur->next;
cur->next = tmp->next;
tmp->next = pre->next;
pre->next = tmp;
}
return dummy->next;
}
};
24. 两两交换链表中的节点(√)
链接: 24. 两两交换链表中的节点.
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if(head == nullptr) { return nullptr; }
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* prev = dummy;
ListNode* node1 = head, *node2 = head->next;
while(node1 && node1->next)
{
node2 = node1->next;
//swap the "next" of prev nodes
prev->next = node1->next; // = node2
//swap the "next" of current nodes
node1->next = node2->next;
node2->next = node1;
prev = node1;
node1 = prev->next;
}
return dummy->next;
}
};
这个版本好理解。
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* cur = dummy;
ListNode* tmp1;
ListNode* tmp2;
while(cur->next != nullptr && cur->next->next != nullptr)
{
tmp1 = cur->next;
tmp2 = cur->next->next;
cur->next = tmp2;
tmp1->next = tmp2->next;
tmp2->next = tmp1;
cur = tmp1;
}
return dummy->next;
}
};
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if(head == nullptr) { return nullptr; }
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* cur = dummy;
while((cur->next != nullptr) && (cur->next->next != nullptr))
{
ListNode* tmp1 = cur->next;
ListNode* tmp2 = cur->next->next->next;
cur->next = cur->next->next;
cur->next->next = tmp1;
tmp1->next = tmp2;
cur = cur->next->next;
}
return dummy->next;
}
};
面试题 02.05. 链表求和
链接: 面试题 02.05. 链表求和.
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode dummy(0);
ListNode* p = &dummy;
int cn = 0;
while(l1 || l2)
{
int val = cn + (l1 ? l1->val : 0) + (l2 ? l2->val : 0);
cn = val / 10;
val = val % 10;
p->next = new ListNode(val);
p = p->next;
if(l1)
{
l1 = l1->next;
}
if(l2)
{
l2 = l2->next;
}
}
if(cn != 0)
{
p->next = new ListNode(cn);
p = p->next;
}
return dummy.next;
}
};
88. 合并两个有序数组(√)
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int p1 = m - 1, p2 = n - 1, cur = m + n - 1;
while(p1 >= 0 && p2 >= 0)
{
nums1[cur--] = nums1[p1] > nums2[p2] ? nums1[p1--] : nums2[p2--];
}
while(p2 >= 0)
{
nums1[cur--] = nums2[p2--];
}
}
};
21. 合并两个有序链表(√)
链接: 21. 合并两个有序链表.
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* dummy = new ListNode(0);
ListNode* cur = dummy;
while(l1 && l2)
{
if(l1->val <= l2->val)
{
cur->next = l1;
l1 = l1->next;
}
else
{
cur->next = l2;
l2 = l2->next;
}
cur = cur->next;
}
cur->next = (l1 != nullptr) ? l1 : l2;
return dummy->next;
}
};
23. 合并K个升序链表(hard)(√)
链接: 23. 合并K个升序链表.
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
private:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2)
{
ListNode* dummy = new ListNode(0);
ListNode* cur = dummy;
while(l1 && l2)
{
if(l1->val <= l2->val)
{
cur->next = l1;
l1 = l1->next;
}
else
{
cur->next = l2;
l2 = l2->next;
}
cur = cur->next;
}
cur->next = (l1 != nullptr) ? l1 : l2;
return dummy->next;
}
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
if(lists.empty()) return nullptr;
ListNode* p = lists[0];
for(int i=1; i<lists.size(); ++i)
{
p = mergeTwoLists(p, lists[i]);
}
return p;
}
};
148. 排序链表
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
if(head == nullptr || head->next == nullptr) return head;
ListNode* head1 = head;
ListNode* head2 = split(head);
head1 = sortList(head1);
head2 = sortList(head2);
return merge(head1, head2);
}
ListNode* split(ListNode* node){
ListNode* slow = node;
ListNode* fast = node->next;
while(fast && fast->next){
slow = slow->next;
fast = fast->next->next;
}
ListNode* splitHead = slow->next;
slow->next = nullptr;
return splitHead;
}
ListNode* merge(ListNode* node1, ListNode* node2){
ListNode* p1 = node1;
ListNode* p2 = node2;
ListNode* dummy = new ListNode(0);
ListNode* p = dummy;
while(p1 && p2){
if(p1->val < p2->val){
p->next = p1;
p1 = p1->next;
}
else{
p->next = p2;
p2 = p2->next;
}
p = p->next;
}
p->next = (p1 == nullptr) ? p2 : p1;
return dummy->next;
}
};
138. 复制带随机指针的链表
链接: 138. 复制带随机指针的链表.