書接上回:
leetcode hot100 鏈表(一)-CSDN博客
8.刪除鏈表的倒數第N個結點
class Solution {
public:ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode* curr=head;int len=0;while(curr){curr=curr->next;len++;}int pos=len-n;if(pos==0){ListNode* newHead=head->next;return newHead;}curr=head;while(--pos) curr=curr->next; //目標是把curr移動到要刪除結點的前面curr->next=curr->next->next;return head;}
};
9.兩兩交換鏈表中的結點
????????參考leetcode靈神題解:
class Solution {
public:ListNode* swapPairs(ListNode* head) {ListNode* dummy=new ListNode(0,head); //dummy->val=0&&dummy->next=head;ListNode* node0=dummy;ListNode* node1=head;while(node1&&node1->next){ListNode* node2=node1->next;ListNode* node3=node2->next;node0->next=node2;node2->next=node1;node1->next=node3;node0=node1;node1=node3;}return dummy->next;}
};
10.k個一組反轉鏈表
? ? ? ? 和上題使用了相同的命名體系。
class Solution {
public:ListNode* reverseKGroup(ListNode* head, int k) {ListNode* dummy=new ListNode(0,head);ListNode* node0=dummy;ListNode* node1=node0->next;while(node1&&node1->next){ListNode* node2=node1->next;ListNode* cnt=node2;for(int i=1;i<k;i++){if(cnt==nullptr) return dummy->next;cnt=cnt->next;}for(int i=1;i<k;i++){node1->next=node2->next;node2->next=node0->next; //node0->next始終指向當前鏈表的頭部node0->next=node2;node2=node1->next;}node0=node1;node1=node0->next;}return dummy->next;}
};
11.隨機鏈表的復制
????????哈希映射法建立新鏈表結點與原節點的映射關系。
class Solution {
public:unordered_map<Node*,Node*> map; //存儲原鏈表節點到新鏈表節點的映射Node* copyRandomList(Node* head) {if(!head) return nullptr;//檢查當前節點是否已經在哈希表中(即是否已經被復制過)//如果節點未被復制過,則創建一個新節點,值與原節點相同,并將原節點和新節點的映射存入哈希表if(!map.count(head)){Node* newHead=new Node(head->val);map[head]=newHead;//遞歸復制next指針指向的鏈表部分和random指針指向的節點newHead->next=copyRandomList(head->next);newHead->random=copyRandomList(head->random);}return map[head]; //返回頭結點在新鏈表中的映射}
};
12.排序鏈表
? ? ? ? 類似歸并排序方法,先二分找到中點(通過快慢指針法),再對左右兩邊分別排序,最后合并兩部分。
class Solution {// 鏈表的中間結點(快慢指針)ListNode* middleNode(ListNode* head) {ListNode* pre=head;ListNode* slow=head;ListNode* fast=head;while (fast&&fast->next) {pre=slow; // 記錄 slow 的前一個節點slow=slow->next;fast=fast->next->next;}pre->next=nullptr; // 斷開 slow 的前一個節點和 slow 的連接return slow; // 鏈表后半部分}// 合并兩個有序鏈表(雙指針),歸并思想ListNode* merge(ListNode* list1, ListNode* list2) {ListNode dummy; // 用哨兵節點簡化代碼邏輯ListNode* cur=&dummy; // cur 指向新鏈表的末尾while(list1&&list2){if(list1->val<=list2->val){cur->next=list1; // 把 list1 加到新鏈表中list1=list1->next;} else{ cur->next=list2;list2=list2->next;}cur=cur->next;}cur->next=list1?list1:list2; // 拼接剩余鏈表return dummy.next;}
public:ListNode* sortList(ListNode* head) {if (!head||!head->next) return head;// 找到中間節點 head2,并斷開 head2 與其前一個節點的連接,然后分治、合并// 比如 head=[4,2,1,3],那么 middleNode 調用結束后 head=[4,2] head2=[1,3]ListNode* head2 = middleNode(head);head=sortList(head);head2=sortList(head2);return merge(head, head2);}
};
13.合并k個升序鏈表
? ? ? ? 利用小根堆實現,小根堆里維護每個非空鏈表未被處理的第一個結點。
class Solution {
public:ListNode* mergeKLists(vector<ListNode*>& lists) {struct Cmp{bool operator()(ListNode* a, ListNode* b){return a->val>b->val;}};priority_queue<ListNode*,vector<ListNode*>,Cmp> min_heap; //優先隊列模擬小根堆for(ListNode* node:lists){if (node) min_heap.push(node); //把所有非空鏈表的頭結點入堆 }ListNode dummy(0); ListNode* tail=&dummy; //tail負責維護合并后的新鏈表while(!min_heap.empty()){ListNode* min_node=min_heap.top(); //剩余結點中的最小結點min_heap.pop(); if(min_node->next) min_heap.push(min_node->next);tail->next=min_node; //把min_node添加到新鏈表末尾tail=tail->next; //準備合并下一個結點}return dummy.next;}
};
14.LRU緩存
struct DLinkedNode {int key, value;DLinkedNode* prev;DLinkedNode* next;DLinkedNode():key(0),value(0),prev(nullptr),next(nullptr){}DLinkedNode(int _key,int _value):key(_key),value(_value),prev(nullptr),next(nullptr){}
};
class LRUCache {
private:unordered_map<int, DLinkedNode*> cache;DLinkedNode* head;DLinkedNode* tail;int size;int capacity;
public:LRUCache(int _capacity): capacity(_capacity), size(0) {// 使用偽頭部和偽尾部節點head = new DLinkedNode();tail = new DLinkedNode();head->next=tail;tail->prev=head;}int get(int key){if(!cache.count(key)) return -1;// 如果 key 存在,先通過哈希表定位,再移到頭部DLinkedNode* node=cache[key];moveToHead(node);return node->value;}void put(int key, int value) {if (!cache.count(key)) {// 如果 key 不存在,創建一個新的節點DLinkedNode* node = new DLinkedNode(key, value);// 添加進哈希表cache[key] = node;// 添加至雙向鏈表的頭部addToHead(node);size++;if(size>capacity) {// 如果超出容量,刪除雙向鏈表的尾部節點DLinkedNode* removed = removeTail();// 刪除哈希表中對應的項cache.erase(removed->key);// 防止內存泄漏delete removed;size--;}}else {// 如果 key 存在,先通過哈希表定位,再修改 value,并移到頭部DLinkedNode* node = cache[key];node->value = value;moveToHead(node);}}void addToHead(DLinkedNode* node) {node->prev=head;node->next=head->next;head->next->prev=node;head->next=node;}void removeNode(DLinkedNode* node) {node->prev->next=node->next;node->next->prev=node->prev;}void moveToHead(DLinkedNode* node){removeNode(node);addToHead(node);}DLinkedNode* removeTail(){DLinkedNode* node=tail->prev;removeNode(node);return node;}
};