leetcode hot100 链表(二)
书接上回:
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;}
};