改结构
1. 反转单链表
//用大小为三个节点的滑动窗口顺序扫描改指针
ListNode* reverseList(ListNode *head) {
ListNode *prev=NULL, *curr=head, *next;
while(curr!=NULL) { //扫描, 次数一共为要转的节点数
next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
return prev;
}
# 以下为递归解法, 因为递归天然记住当前节点, 所以仅仅改下指针即可
def reverseList(self, head):
if head == None or head.next == None:
return head
node = self.reverseList(head.next)
head.next.next = head
head.next = None # 需要这一步
return node
2. 在第m和n闭区间内反转单链表
ListNode* reverseBetween(ListNode *head, int m, int n) {
ListNode *prev_head=new ListNode(0); prev_head->next=head; //构建超头
ListNode *prev_left=prev_head, *next_right=head;
for(int i=1; i<m; i++) prev_left=prev_left->next; //左前驱
for(int i=0; i<n; i++) next_right=next_right->next; //右后驱
//套用一般反转链表代码
ListNode *prev=next_right, *curr=prev_left->next, *next;
for(int i=m; i<=n; i++) { //这里次数为要转的节点数
next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
//前面接起来
prev_left->next = prev;
return prev_head->next;
}
3. K组反转单链表
1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
ListNode* reverseKGroup(ListNode* head, int k) {
int len = 0;
for(ListNode *p=head; p!=NULL; p=p->next) len++;
for(int i=0; i<len/k; i++)
head = reverseBetween(head, i*k+1, (i+1)*k);
return head;
}
4. 旋转单链表
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
ListNode* rotateRight(ListNode* head, int k) {
int len=0;
for(ListNode *p=head; p!=NULL; p=p->next) len++;
k = len!=0 ? k % len : 0;
if (k==0) return head;
ListNode *slow=head, *fast=head;
while(k--) fast = fast->next;
while(fast->next!=NULL) { // 找两前驱
fast = fast->next;
slow = slow->next;
}
ListNode *new_head = slow->next;
slow->next = NULL;
fast->next = head;
return new_head;
}
5. 奇偶链表
给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。
请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL
ListNode* oddEvenList(ListNode* head) {
if(head==NULL) return NULL;
ListNode *odd=head, *even=head->next; // 双指针
ListNode *head_odd=odd, *head_even=even;
while(even!=NULL&&even->next!=NULL) {
odd->next = odd->next->next;
even->next = even->next->next;
odd = odd->next;
even = even->next;
}
odd->next = head_even;
return head_odd;
}
6. 二路有序链表归并
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode pi; // 超头
ListNode *p1=l1, *p2=l2, *p=π
while(p1 != nullptr && p2 != nullptr) {
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?p1:p2; //剩余接起来
return pi.next;
}
7. 链表归并排序
ListNode* sortList(ListNode* head) {
// 注意跳出条件与数组归并不一样
if (head==NULL||head->next==NULL) return head;
// 从中间拆表
ListNode *slow=head, *fast=head, *pre;
while(fast!=NULL&&fast->next!=NULL) {
pre = slow;
slow = slow->next;
fast = fast->next->next;
}
pre->next = NULL;
// 归并排序
ListNode *l1 = sortList(head);
ListNode *l2 = sortList(slow);
return mergeTwoLists(l1, l2);
}
8. 链表去重
ListNode* removeDuplicateNodes(ListNode* head) {
head = sortList(head);
for(ListNode *p=head; p!=NULL; ) {
while(p->next&&(p->next->val==p->val)) {
ListNode *temp = p->next;
p->next = temp->next;
delete temp;
}
p = p->next;
}
return head;
}
递归
1. 从尾到头打印链表
class Solution {
public:
vector<int> reversePrint(ListNode* head) {
vector<int> res;
traceback(head,res);
return res;
}
void traceback(ListNode* head, vector<int> &trace) {
if(head==NULL) return;
traceback(head->next, trace);
trace.push_back(head->val);
}
};
2. 复杂链表复制
class Solution {
public:
unordered_map<Node*, Node*> map;
Node* copyRandomList(Node* head) {
if(head==NULL) return NULL;
if(map.count(head)) return map[head];
Node *node = new Node(head->val);
map[head] = node;
node->next = copyRandomList(head->next);
node->random = copyRandomList(head->random);
return node;
}
};
检测
1. 环路检测
ListNode *detectCycle(ListNode *head) {
ListNode *slow=head, *fast=head;
while(fast!=NULL && fast->next!=NULL) {
slow = slow->next;
fast = fast->next->next;
if(slow==fast) { // 存在环
fast = head; //快指针到最前面
while(slow!=fast) { //找第一个相遇点
slow = slow->next; //协同步进
fast = fast->next;
}
return slow;
}
}
return NULL;
}
2. 找到倒数k个节点的值
int kthToLast(ListNode* head, int k) {
ListNode *slow=head, *fast=head;
while(k--) fast = fast->next;
while(fast!=NULL) {
slow = slow->next;
fast = fast->next;
}
return slow->val;
}
LRU缓存机制实现
/** LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
* int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值否则返回-1
* void put(int key, int value) 如果关键字已经存在,
* 则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。
* 当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,
* 从而为新的数据值留出空间。*/
class LRUCache {
public:
LRUCache(int capacity) {
cap_ = capacity;
num_items_ = 0;
}
int get(int key) {
if(map_.count(key)) {
auto it = map_[key];
pair<int, int> item = *it;
lru_.erase(it);
lru_.push_front(item);
map_[key] = lru_.begin();
return item.second;
}
else return -1;
}
void put(int key, int value) {
if(map_.count(key)) {
auto it = map_[key];
pair<int, int> item = *it;
item.second = value;
lru_.erase(it);
lru_.push_front(item);
map_[key] = lru_.begin();
}
else {
num_items_++;
if(num_items_>cap_) {
map_.erase(lru_.back().first);
lru_.pop_back();
num_items_ = cap_;
}
lru_.push_front(pair<int, int>(key, value));
map_[key] = lru_.begin();
}
}
private:
list<pair<int, int>> lru_;
unordered_map<int, list<pair<int, int>>::iterator> map_;
int cap_, num_items_;
};