刷题笔记
- 链表leetcode专栏
- leetcode 23 合并K个升序链表(采用小根堆来拿k个Node中的MinNode)
- leetcode 23 合并K个升序链表(递归分治思想+合并2个升序链表算法)
- leetcode 203 移除链表元素
- leetcode 707 设计链表
- leetcode 206 翻转链表
- leetcode 92 翻转链表II
- leetcode 24 两两交换链表中的节点
- leetcode 19 删除链表的倒数第 N 个结点(采用双指针fast和slow)
- leetcode 876 链表的中间结点(采用双指针fast和slow)
- leetcode 160 链表相交(两种方法)
- leetcode 141 环形链表(采用双指针fast和slow)
- leetcode 142 环形链表 II(环形入口的判定条件)
- leetcode 328 奇偶链表
- leetcode 234 回文链表(采用slow和fast双指针,slow边遍历边逆转链表)
- leetcode 21 合并两个有序链表(类似归并排序的Merge)
- leetcode 2 两数相加
- leetcode 430 扁平化多级双向链表
- leetcode 138 复制带随机指针的链表
- leetcode 61 旋转链表
链表leetcode专栏
leetcode 23 合并K个升序链表(采用小根堆来拿k个Node中的MinNode)
//采用构建最小堆来拿到每次K个链表结点中的最小值的那个结点
//时间复杂度O(NlogK)
class Solution {
public:
struct cmp {
bool operator() (ListNode* l1, ListNode* l2) {
return l1->val > l2->val;
}
};
ListNode* mergeKLists(vector<ListNode*>& lists) {
priority_queue<ListNode*, vector<ListNode*>, cmp> pq;
for (int i = 0; i < lists.size(); i++) {
if (lists[i] != NULL) {
pq.push(lists[i]);
}
}
ListNode* dummyNode = new ListNode();
ListNode* cur = dummyNode;
while (!pq.empty()) {
ListNode* p = pq.top();
pq.pop();
if (p->next != NULL) {
pq.push(p->next);
}
cur->next = p;
cur = p;
}
return dummyNode->next;
}
};
leetcode 23 合并K个升序链表(递归分治思想+合并2个升序链表算法)
class Solution {
public:
ListNode* mergeTwoLists(ListNode* p, ListNode* q) { //合并两个链表的算法
ListNode* dummyNode = new ListNode();
ListNode* cur = dummyNode;
while (p != NULL && q != NULL) {
if (p->val <= q->val) {
cur->next = p;
p = p->next;
}
else {
cur->next = q;
q = q->next;
}
cur = cur->next;
}
if (p != NULL) {
cur->next = p;
}
if (q != NULL) {
cur->next = q;
}
return dummyNode->next;
}
ListNode* mergeKLists(vector<ListNode*>& lists) { //考虑采用分治
if (lists.size() == 0) {
return NULL;
}
if (lists.size() == 1) {
return lists[0];
}
// if (lists.size() == 2) { //这里的代码可以不用
// return mergeTwoLists(lists[0], lists[1]);
// }
int mid = lists.size() / 2;
vector<ListNode*> lists1;
vector<ListNode*> lists2;
for (int i = 0; i < mid; i++) {
lists1.push_back(lists[i]);
}
for (int i = mid; i < lists.size(); i++) {
lists2.push_back(lists[i]);
}
ListNode* p1 = mergeKLists(lists1);
ListNode* p2 = mergeKLists(lists2);
return mergeTwoLists(p1, p2);
}
};
leetcode 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) {
ListNode* dummyNode = new ListNode();
dummyNode->next = head;
ListNode* cur = head;
ListNode* pre = dummyNode;
while (cur != nullptr) {
if (cur->val == val) {
ListNode* tmp = cur;
pre->next = cur->next;
cur = cur->next;
delete tmp;
}
else {
pre = cur;
cur = cur->next;
}
}
return dummyNode->next;
}
};
leetcode 707 设计链表
设计链表问题主要在于虚拟头结点的使用,和题目中所给的index的要求,index是从0开始的
class MyLinkedList {
public:
struct LinkNode {
int val;
LinkNode* next;
LinkNode(int x) : val(x), next(nullptr) {}
};
MyLinkedList() {
_dummyNode = new LinkNode(0);
_size = 0;
}
int get(int index) {
if (index >= _size) {
return -1;
}
LinkNode* cur = _dummyNode;
while (index != -1) {
cur = cur->next;
index--;
}
return cur->val;
}
void addAtHead(int val) {
LinkNode* tmp = new LinkNode(val);
tmp->next = _dummyNode->next;
_dummyNode->next = tmp;
_size++;
}
void addAtTail(int val) {
LinkNode* tmp = new LinkNode(val);
LinkNode* cur = _dummyNode;
while (cur->next != nullptr) {
cur = cur->next;
}
cur->next = tmp;
_size++;
}
void addAtIndex(int index, int val) {
LinkNode* tmp = new LinkNode(val);
if (index > _size) {
return;
}
else if (index < 0) {
tmp->next = _dummyNode->next;
_dummyNode->next = tmp;
}
else if (index == _size) {
LinkNode* cur = _dummyNode;
while (cur->next != nullptr) {
cur = cur->next;
}
cur->next = tmp;
}
else {
LinkNode* pre = _dummyNode;
LinkNode* cur = _dummyNode;
while (index != -1) {
pre = cur;
cur = cur->next;
index--;
}
tmp->next = pre->next;
pre->next = tmp;
}
_size++;
}
void deleteAtIndex(int index) {
if (index >= _size || index < 0) {
return;
}
LinkNode* pre = _dummyNode;
LinkNode* cur = _dummyNode;
while (index != -1) {
pre = cur;
cur = cur->next;
index--;
}
LinkNode* tmp = cur;
pre->next = cur->next;
delete tmp;
_size--;
}
private:
LinkNode* _dummyNode;
int _size;
};
leetcode 206 翻转链表
采用三个指针
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* pre = nullptr;
ListNode* cur = head;
ListNode* after = nullptr;
while (cur != nullptr) {
after = cur->next;
cur->next = pre;
pre = cur;
cur = after;
}
return pre;
}
};
采用递归方法
class Solution {
public:
ListNode* reverseList(ListNode* head) {
// ListNode* cur = head;
// ListNode* pre = NULL;
return reverse(nullptr, head);
}
ListNode* reverse(ListNode* pre, ListNode* cur) {
if (cur == nullptr) {
return pre;
}
ListNode* after = cur->next;
cur->next = pre;
// pre = cur;
// cur = after;
return reverse(cur, after);
}
};
错误写法,reverse中传入cur->next之前,它的值已经被pre覆盖了
class Solution {
public:
ListNode* reverseList(ListNode* head) {
return reverse(NULL, head);
}
ListNode* reverse(ListNode* pre, ListNode* cur) {
if (cur == NULL) {
return pre;
}
//ListNode* aft = cur->next;
cur->next = pre;
return reverse(cur, cur->next);
}
};
leetcode 92 翻转链表II
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* pre = nullptr;
ListNode* cur = head;
ListNode* after = nullptr;
while (cur != nullptr) {
after = cur->next;
cur->next = pre;
pre = cur;
cur = after;
}
return pre;
}
ListNode* reverseBetween(ListNode* head, int left, int right) {
ListNode* dummyNode = new ListNode(-1);
dummyNode->next = head;
ListNode* prel = NULL;
ListNode* l = dummyNode;
while (left--) {
prel = l;
l = l->next;
}
ListNode* aftr = NULL;
ListNode* r = dummyNode;
while (right--) {
r = r->next;
}
aftr = r->next;
r->next = NULL;
prel->next = reverseList(l);
while(prel->next) prel = prel->next;
prel->next = aftr;
return dummyNode->next;
}
};
leetcode 24 两两交换链表中的节点
画图按照转换的逻辑步骤写代码,一次转换涉及到三个节点。
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyNode = new ListNode();
dummyNode->next = head;
ListNode* cur = dummyNode;
while (cur->next != nullptr && cur->next->next != nullptr) {
ListNode* node1 = cur->next;
ListNode* node2 = cur->next->next;
ListNode* node3 = cur->next->next->next;
cur->next = node2;
node2->next = node1;
node1->next = node3;
cur = cur->next->next;
}
return dummyNode->next;
}
};
leetcode 19 删除链表的倒数第 N 个结点(采用双指针fast和slow)
采用双指针,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾,删掉slow所指向的节点就可以了。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* fast = head;
ListNode* slow = head;
while (n--) {
fast = fast->next;
}
ListNode* pre = NULL;
while (fast && slow) {
fast = fast->next;
pre = slow;
slow = slow->next;
}
if (pre) pre->next = slow->next;
else return slow->next;
return head;
}
};
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyNode = new ListNode();
dummyNode->next = head;
ListNode* fast = dummyNode;
ListNode* slow = dummyNode;
ListNode* preslow = nullptr;
while (fast != nullptr) {
while (n) {
fast = fast->next;
n--;
}
preslow = slow;
slow = slow->next;
fast = fast->next;
}
ListNode* tmp = slow;
preslow->next = slow->next;
delete tmp;
return dummyNode->next;
}
};
leetcode 876 链表的中间结点(采用双指针fast和slow)
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode* fast = head;
ListNode* slow = head;
while (fast != NULL && fast->next != NULL) {
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
};
leetcode 160 链表相交(两种方法)
解决这个问题的关键是,通过某些方式,让 p1 和 p2 能够同时到达相交节点 c1。
//求出两个链表的长度差值dst,先让长度较长的链表先走dst,然后两个链表一起走,遇到第一个相同的节点就是相等的
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA;
ListNode* curB = headB;
int dista = 0;
int distb = 0;
int dist = 0;
while (curA) {
curA = curA->next;
dista++;
}
while (curB) {
curB = curB->next;
distb++;
}
dist = abs(dista-distb);
ListNode* curL;
ListNode* curS;
if (dista >= distb) {
curL = headA;
curS = headB;
}
else {
curL = headB;
curS = headA;
}
while (dist--) curL = curL->next;
while (curL && curS) {
if (curL == curS) {
return curL;
}
curL = curL->next;
curS = curS->next;
}
return NULL;
}
};
我们可以让 p1 遍历完链表 A 之后开始遍历链表 B,让 p2 遍历完链表 B 之后开始遍历链表 A,这样相当于「逻辑上」两条链表接在了一起。
如果这样进行拼接,就可以让 p1 和 p2 同时进入公共部分,也就是同时到达相交节点 c1。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA;
ListNode* curB = headB;
while (curA != curB) {
if (!curA) curA = headB;
else curA = curA->next;
if (!curB) curB = headA;
else curB = curB->next;
}
return curA;
}
};
leetcode 141 环形链表(采用双指针fast和slow)
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
bool flag = false;
while (fast != NULL && fast->next != NULL) {
fast = fast->next->next;
slow = slow->next;
if (slow == fast) {
flag = true;
break;
}
}
return flag;
}
};
leetcode 142 环形链表 II(环形入口的判定条件)
//从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* slow = head;
ListNode* fast = head;
while (fast != NULL && fast->next != NULL) { //确保fast指针移动范围的有效
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
ListNode* index1 = fast;
ListNode* index2 = head;
while (index1 != index2) {
index1 = index1->next;
index2 = index2->next;
}
return index2;
}
}
return NULL;
}
};
leetcode 328 奇偶链表
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
if (head == NULL) return NULL;
ListNode* odd = head;
ListNode* even = head->next;
ListNode* evenStart = even;
while (even != NULL && even->next != NULL) {
odd->next = even->next;
odd = odd->next;
even->next = odd->next;
even = even->next;
}
odd->next = evenStart;
return head;
}
};
leetcode 234 回文链表(采用slow和fast双指针,slow边遍历边逆转链表)
//采用快慢两个指针,快指针到达末尾,慢指针到达中间,慢指针在遍历过程中顺便翻转前面的链表
class Solution {
public:
bool isPalindrome(ListNode* head) {
ListNode* slow = head;
ListNode* fast = head;
ListNode* cur = NULL;
ListNode* pre = NULL;
while (fast != NULL && fast->next != NULL) {
cur = slow;
slow = slow->next;
fast = fast->next->next;
cur->next = pre;
pre = cur;
}
if (fast != NULL) { //处理结点为奇数的情况
slow = slow->next;
}
while (cur != NULL && slow != NULL) {
if (cur->val != slow->val) {
return false;
}
cur = cur->next;
slow = slow->next;
}
return true;
}
};
leetcode 21 合并两个有序链表(类似归并排序的Merge)
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode* dummyNode = new ListNode();
ListNode* cur = dummyNode;
while (list1 != NULL && list2 != NULL) {
if (list1->val < list2->val) {
cur->next = list1;
list1 = list1->next;
}
else {
cur->next = list2;
list2 = list2->next;
}
cur = cur->next;
}
if (list1 != NULL) {
cur->next = list1;
}
if (list2 != NULL) {
cur->next = list2;
}
return dummyNode->next;
}
};
leetcode 2 两数相加
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* dummyNode = new ListNode();
ListNode* cur = dummyNode;
int carry = 0;
while (l1 != NULL || l2 != NULL) {
int val1 = l1 == NULL ? 0 : l1->val;
int val2 = l2 == NULL ? 0 : l2->val;
int sum = val1 + val2 + carry;
carry = sum / 10;
sum = sum % 10;
cur->next = new ListNode(sum);;
cur = cur->next;
if (l1 != NULL) l1 = l1->next;
if (l2 != NULL) l2 = l2->next;
}
if (carry == 1) {
cur->next = new ListNode(1);
}
return dummyNode->next;
}
};
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
int carry = 0;
ListNode* dummyNode = new ListNode();
ListNode* r = dummyNode;
while (l1 != NULL && l2 != NULL) {
int a = l1->val;
int b = l2->val;
int c = (a + b + carry) % 10;
carry = (a + b + carry) / 10;
ListNode* p = new ListNode(c);
r->next = p;
r = p;
l1 = l1->next;
l2 = l2->next;
}
ListNode* q;
if (l1 != NULL) q = l1;
else q = l2;
while (q != NULL) {
int a = q->val;
int c = (a + carry) % 10;
carry = (a + carry) / 10;
ListNode* p = new ListNode(c);
r->next = p;
r = p;
q = q->next;
}
if (carry == 1) {
ListNode* p = new ListNode(carry);
r->next = p;
r = p;
}
return dummyNode->next;
}
};
leetcode 430 扁平化多级双向链表
//采用迭代法,按照段进行遍历,将其链接起来
class Solution {
public:
Node* flatten(Node* head) {
Node* dummyNode = new Node();
dummyNode->next = head;
while (head != NULL) {
if (head->child != NULL) {
Node* tmp = head->next;
head->next = head->child;
head->child->prev = head;
Node* last = head->child;
head->child = NULL;
while (last->next != NULL) {
last = last->next;
}
last->next = tmp;
if(tmp != NULL) tmp->prev = last;
}
head = head->next;
}
return dummyNode->next;
}
};
//采用栈来保存节点
class Solution {
public:
Node* flatten(Node* head) {
Node* dummy = new Node();
dummy->next = head;
stack<Node*> sck;
while (head != NULL) {
if (head->child != NULL) { //当该节点处有child分支时,并入该分支进主干
Node* tmp = head->next;
head->next = head->child;
head->child->prev = head;
head->child = NULL; //为了恢复完整的双链表结构,child指针合入用完后需要置空
if (tmp != NULL) sck.push(tmp); //压栈,以备后面续接链表
}
else { // head->child == NULL
if (head->next == NULL && !sck.empty()) { //续接链表
Node* tmp = sck.top();
sck.pop();
head->next = tmp;
tmp->prev = head;
}
}
head = head->next; //每轮处理完后,接着处理下一个结点,直到所有节点都被处理完
}
return dummy->next;
}
};
leetcode 138 复制带随机指针的链表
采用递归进行处理
class Solution {
unordered_map<Node*, Node*> hashMap;
public:
Node* copyRandomList(Node* head) {
if (!head) return NULL;
Node* newNode = new Node(head->val);
hashMap[head] = newNode;
newNode->next = copyRandomList(head->next);
if (head->random) {
newNode->random = hashMap[head->random];
}
return newNode;
}
};
采用迭代法
class Solution {
public:
Node* copyRandomList(Node* head) {
unordered_map<Node*, Node*> hashMap;
Node* cur = head;
while (cur != NULL) {
Node* tmp = new Node(cur->val);
hashMap[cur] = tmp;
cur = cur->next;
}
cur = head;
while (cur != NULL) {
Node* tmp = hashMap[cur];
if(cur->next) tmp->next = hashMap[cur->next];
else tmp->next = NULL;
tmp->random = hashMap[cur->random];
cur = cur->next;
}
return hashMap[head];
}
};
class Solution {
public:
Node* copyRandomList(Node* head) {
if (head == NULL) return NULL;
unordered_map<Node*, int> hashMap;
vector<Node*> vec;
Node* cur = head;
int idx = 0;
while (cur != NULL) {
hashMap.insert(pair<Node*, int>(cur, idx));
vec.push_back(new Node(cur->val));
cur = cur->next;
idx++;
}
cur = head;
idx = 0;
vec.push_back(NULL);
while (cur != NULL) {
vec[idx]->next = vec[idx+1];
Node* tmp = cur->random;
if (tmp == NULL) {
vec[idx]->random = NULL;
}
else {
vec[idx]->random = vec[hashMap[tmp]];
}
cur = cur->next;
idx++;
}
return vec[0];
}
};
leetcode 61 旋转链表
//本质上是将尾部向前数第K个元素作为头,原来的头接到原来的尾上
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if (k == 0 || !head || !head->next) return head;
int cnt = 1;
ListNode* cur = head;
while (cur->next != NULL) {
cnt++;
cur = cur->next;
}
k = k % cnt;
if(k == 0) return head;
cur->next = head; //需要翻转,首尾相连
for (int i = 0; i < cnt - k; i++) { //找到倒数第k+1个节点
cur = cur->next;
}
ListNode* newHead = cur->next;
cur->next = NULL;
return newHead;
}
};