1. 链表类问题技巧:
  2. 1】虚拟头节点dummyNode 的创建 往往都是为了能够方面操作 头节点 而来的;
  3. 2】双指针 在多个情境下的使用;
一级类目 二级类型/题目 三级类目/题目
单链表 链表中的加法 2. 两数相加
面试题 02.05. 链表求和
445. 两数相加 II
反转链表 206. 反转链表
92. 反转链表 II
剑指 Offer 06. 从尾到头打印链表
143. 重排链表
25. K 个一组翻转链表 高频
234. 回文链表
链表相交 160. 相交链表
环形链表 141. 环形链表 重点
142. 环形链表 II 重点
倒数第K个节点 剑指 Offer 22. 链表中倒数第k个节点
删除链表节点 237. 删除链表中的节点
19. 删除链表的倒数第 N 个结点 高频
83. 删除排序链表中的重复元素
82. 删除排序链表中的重复元素 II 重点
面试题 02.01. 移除重复节点
203. 移除链表元素
排序链表 147. 对链表进行插入排序
148. 排序链表
合并链表 剑指 Offer 25. 合并两个排序的链表
21. 合并两个有序链表
1669. 合并两个链表
23. 合并K个升序链表 高频
双向链表 面试题 16.25. LRU 缓存
460. LFU 缓存

单链表

链表中的加法

2. 两数相加

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode() : val(0), next(nullptr) {}
  7. * ListNode(int x) : val(x), next(nullptr) {}
  8. * ListNode(int x, ListNode *next) : val(x), next(next) {}
  9. * };
  10. */
  11. class Solution {
  12. public:
  13. ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
  14. ListNode *head=nullptr,*tail=nullptr;
  15. int first=0,second=0;
  16. int carry=0;
  17. while(l1||l2){
  18. first=l1?l1->val:0;
  19. second=l2?l2->val:0;
  20. int sum=first+second+carry;
  21. if(!head){
  22. head=tail=new ListNode(sum%10);
  23. }else {
  24. tail->next=new ListNode(sum%10);
  25. tail=tail->next;
  26. }
  27. carry=sum/10;
  28. if(l1)l1=l1->next;
  29. if(l2)l2=l2->next;
  30. }
  31. if(carry){tail->next=new ListNode(carry);}
  32. return head;
  33. }
  34. };

面试题 02.05. 链表求和

代码和上题一样

445. 两数相加 II

  • 思路

    1. 先分别反转,相加,然后再反转输出;
    1. /**
    2. * Definition for singly-linked list.
    3. * struct ListNode {
    4. * int val;
    5. * ListNode *next;
    6. * ListNode(int x) : val(x), next(NULL) {}
    7. * };
    8. */
    9. class Solution {
    10. public:
    11. ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) {
    12. ListNode *ll1 = reverse(l1);
    13. ListNode *ll2 = reverse(l2);
    14. int sum = 0, carry = 0;
    15. ListNode *head = nullptr, *tail = nullptr;
    16. while (ll1 || ll2) {
    17. int left = ll1 ? ll1->val : 0;
    18. int right = ll2 ? ll2->val : 0;
    19. sum = left + right + carry;
    20. if (!head) {
    21. head = tail = new ListNode(sum % 10);
    22. } else {
    23. tail->next = new ListNode(sum % 10);
    24. tail = tail->next;
    25. }
    26. carry = sum / 10;
    27. if (ll1)ll1 = ll1->next;
    28. if (ll2)ll2 = ll2->next;
    29. }
    30. if (carry) {
    31. tail->next = new ListNode(carry);
    32. }
    33. return reverse(head);
    34. }
    35. ListNode *reverse(ListNode *l) {
    36. if (l == nullptr || l->next == nullptr) {
    37. return l;
    38. }
    39. // 1->2->3
    40. ListNode *prev = nullptr, *next = l;
    41. while (l) {
    42. next = l->next;
    43. l->next = prev;
    44. prev = l;
    45. l = next;
    46. }
    47. return prev;
    48. }
    49. };

    反转链表

    206. 反转链表

    1. class Solution {
    2. public:
    3. ListNode* reverseList(ListNode* head) {
    4. if(head==nullptr){
    5. return head;
    6. }
    7. ListNode* prev=nullptr,*next=nullptr;
    8. while(head!=nullptr){
    9. next=head->next;
    10. head->next=prev;
    11. prev=head;
    12. head=next;
    13. }
    14. return prev;
    15. }
    16. };

    92. 反转链表 II

    这道很经典。(涉及链表的操作多,慢点做)

    1. class Solution {
    2. public:
    3. ListNode *reverse(ListNode *head) {
    4. if (head == nullptr) {
    5. return head;
    6. }
    7. ListNode *prev = nullptr, *next = nullptr;
    8. while (head != nullptr) {
    9. next = head->next;
    10. head->next = prev;
    11. prev = head;
    12. head = next;
    13. }
    14. return prev;
    15. }
    16. /**
    17. * 1->2->3->4->5
    18. * [2,4]
    19. * 1->4->3->2->5
    20. * @param head
    21. * @param left
    22. * @param right
    23. * @return
    24. */
    25. ListNode *reverseBetween(ListNode *head, int left, int right) {
    26. ListNode *dummyNode = new ListNode(-1);
    27. dummyNode->next = head;
    28. ListNode *prev = dummyNode;
    29. for (int i = 0; i < left - 1; i++) {//left=2,left-1=1,
    30. prev = prev->next; // dummyNode 不变,prev 向后移动,移动left-1 步,到 left 前一个节点位置,即此时prev在1位置;
    31. }
    32. ListNode *rightNode = prev;
    33. for (int i = 0; i < right - left + 1; i++) {//right-left+1=3,rightNode从1开始移动三步,到4位置;
    34. rightNode = rightNode->next;
    35. }
    36. // 第三步: 切割子链表出来
    37. ListNode *leftNode = prev->next;// leftNode指向2,即目标片段的开始节点;
    38. ListNode *curr = rightNode->next;// 保存4 之后的链表片段;
    39. //切断链接
    40. prev->next = nullptr;// 1->nullptr
    41. rightNode->next = nullptr;//4->nullptr,此时产生了三个片段
    42. //反转2->3->4 成为 4->3->2
    43. reverse(leftNode);
    44. //接回原链表
    45. prev->next = rightNode;
    46. leftNode->next = curr;
    47. return dummyNode->next;
    48. }
    49. };

    剑指 Offer 06. 从尾到头打印链表

    1. /**
    2. * Definition for singly-linked list.
    3. * struct ListNode {
    4. * int val;
    5. * ListNode *next;
    6. * ListNode(int x) : val(x), next(NULL) {}
    7. * };
    8. */
    9. class Solution {
    10. public:
    11. vector<int> res;
    12. vector<int> reversePrint(ListNode *head) {
    13. while (head != nullptr) {
    14. res.push_back(head->val);
    15. head = head->next;
    16. }
    17. reverse(res.begin(), res.end());
    18. return res;
    19. }
    20. };

    143. 重排链表

    方法一:

    1. /**
    2. * Definition for singly-linked list.
    3. * struct ListNode {
    4. * int val;
    5. * ListNode *next;
    6. * ListNode() : val(0), next(nullptr) {}
    7. * ListNode(int x) : val(x), next(nullptr) {}
    8. * ListNode(int x, ListNode *next) : val(x), next(next) {}
    9. * };
    10. */
    11. class Solution {
    12. public:
    13. void reorderList(ListNode *head) {
    14. if (head == nullptr) {
    15. return;
    16. }
    17. vector<ListNode *> res;
    18. ListNode *node = head;
    19. while (node != nullptr) {
    20. res.emplace_back(node);
    21. node = node->next;
    22. }
    23. int i = 0, j = res.size() - 1;
    24. while (i < j) {
    25. res[i]->next = res[j];
    26. i++;
    27. if (i == j) { break; }
    28. res[j]->next = res[i];
    29. j--;
    30. }
    31. res[i]->next = nullptr;
    32. }
    33. };

    方法二:

    1. class Solution {
    2. public:
    3. ListNode *middleNode(ListNode *head) {
    4. ListNode *slow = head;
    5. ListNode *fast = head;
    6. while (fast->next != nullptr && fast->next->next != nullptr) {
    7. fast = fast->next->next;
    8. slow = slow->next;
    9. }
    10. return slow;
    11. }
    12. ListNode *reverse(ListNode *head) {
    13. if (head == nullptr) { return head; }
    14. ListNode *prev = nullptr, *next = nullptr;
    15. while (head) {
    16. next = head->next;
    17. head->next = prev;
    18. prev = head;
    19. head = next;
    20. }
    21. return prev;
    22. }
    23. //合并两个链表
    24. void mergeList(ListNode *l1, ListNode *l2) {
    25. ListNode *left=nullptr, *right=nullptr;
    26. while (l1 && l2) {
    27. left = l1->next;
    28. right = l2->next;
    29. l1->next = l2;
    30. l1 = left;
    31. l2->next = l1;
    32. l2 = right;
    33. }
    34. }
    35. void reorderList(ListNode *head) {
    36. if (head == nullptr) { return; }
    37. ListNode *mid = middleNode(head);
    38. ListNode *l1 = head;
    39. ListNode *l2 = mid->next;
    40. mid->next = nullptr;
    41. l2 = reverse(l2);
    42. mergeList(l1, l2);
    43. }
    44. };

    25. K 个一组翻转链表

    1. class Solution {
    2. public:
    3. /**
    4. * 不是很好理解; 要修改成自己的方式
    5. * @param head
    6. * @param tail
    7. * @return
    8. */
    9. pair<ListNode *, ListNode *> reverse(ListNode *head, ListNode *tail) {
    10. ListNode *prev = tail->next;
    11. ListNode *p = head;
    12. while (prev != tail) {
    13. ListNode *nex = p->next;
    14. p->next = prev;
    15. prev = p;
    16. p = nex;
    17. }
    18. return {tail, head};
    19. }
    20. ListNode *reverseKGroup(ListNode *head, int k) {
    21. //构建虚拟头结点
    22. ListNode *dummyNode = new ListNode(-1);
    23. dummyNode->next = head;
    24. ListNode *pre = dummyNode;
    25. while (head) {
    26. ListNode *tail = pre;
    27. // 每 k 个处理
    28. for (int i = 0; i < k; i++) {
    29. tail = tail->next;
    30. if (!tail) {
    31. return dummyNode->next;
    32. }
    33. }
    34. ListNode *nex = tail->next;
    35. pair<ListNode *, ListNode *> result = reverse(head, tail);
    36. head = result.first;
    37. tail = result.second;
    38. //把子链表 链接回 原链表中;
    39. pre->next = head;
    40. tail->next = nex;
    41. //
    42. pre = tail;
    43. head = tail->next;
    44. }
    45. return dummyNode->next;
    46. }
    47. };

234. 回文链表

方法一:

image.png

  1. class Solution {
  2. public:
  3. bool isPalindrome(ListNode *head) {
  4. vector<int> res;
  5. while (head) {
  6. res.emplace_back(head->val);
  7. head = head->next;
  8. }
  9. for (int i = 0; i < res.size() / 2; i++) {
  10. if (res[i] != res[res.size() - 1 - i]) {
  11. return false;
  12. }
  13. }
  14. return true;
  15. }
  16. };

方法二:
  1. bool isPalindrome(ListNode *head) {
  2. if (!head || !head->next) {
  3. return true;
  4. }
  5. int size = 0;
  6. ListNode *p1 = head;
  7. while (p1) {
  8. size += 1;
  9. p1 = p1->next;
  10. }
  11. int mid = size >> 1;
  12. ListNode *p2 = head;
  13. while (mid > 0) {
  14. p2 = p2->next;
  15. mid--;
  16. }
  17. ListNode *prev = nullptr, *now = p2, *next = nullptr;
  18. while (now) {
  19. next = now->next;
  20. now->next = prev;
  21. prev = now;
  22. now = next;
  23. }
  24. int step = 0;
  25. while (step < (size >> 1)) {
  26. if (head->val != prev->val) {
  27. return false;
  28. }
  29. head = head->next;
  30. prev = prev->next;
  31. step += 1;
  32. }
  33. return true;
  34. }

链表相交

160. 相交链表

  1. class Solution {
  2. public:
  3. int getListLength(ListNode *head) {
  4. ListNode *tmp = head;
  5. int count = 0;
  6. while (tmp) {
  7. count += 1;
  8. tmp = tmp->next;
  9. }
  10. return count;
  11. }
  12. ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
  13. int len_a = getListLength(headA);
  14. int len_b = getListLength(headB);
  15. int dis = abs(len_a - len_b);
  16. if (len_a > len_b) {
  17. for (int i = 0; i < dis; i++) {
  18. headA = headA->next;
  19. }
  20. } else {
  21. for (int i = 0; i < dis; i++) {
  22. headB = headB->next;
  23. }
  24. }
  25. while (headA != nullptr && headB != nullptr) {
  26. if (headA == headB) {
  27. return headA;
  28. }
  29. headA = headA->next;
  30. headB = headB->next;
  31. }
  32. return nullptr;
  33. }
  34. };

环形链表

141. 环形链表

  1. //快慢指针,一个走一步,一个走两步,如果有环,那么必然相遇
  2. //如果没还,在两指针走到头停止。
  3. class Solution {
  4. public:
  5. bool hasCycle(ListNode *head) {
  6. if (head == nullptr) {
  7. return false;
  8. }
  9. ListNode *res = head;
  10. while (head && res && res->next) {
  11. head = head->next;
  12. res = res->next->next;
  13. if (head == res) {
  14. return true;
  15. }
  16. }
  17. return false;
  18. }
  19. };

142. 环形链表 II

题解

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode(int x) : val(x), next(NULL) {}
  7. * };
  8. */
  9. class Solution {
  10. public:
  11. ListNode *detectCycle(ListNode *head) {
  12. if (head == nullptr) {
  13. return nullptr;
  14. }
  15. ListNode *slow = head, *fast = head;
  16. while (fast) {
  17. slow = slow->next;
  18. if(!fast->next){
  19. return nullptr;
  20. }
  21. fast = fast->next->next;
  22. if (fast == slow) {
  23. ListNode *res = head;
  24. while (res != slow) {
  25. res = res->next;
  26. slow = slow->next;
  27. }
  28. return res;
  29. }
  30. }
  31. return nullptr;
  32. }
  33. };

倒数第K个节点

剑指 Offer 22. 链表中倒数第k个节点

  1. class Solution {
  2. public:
  3. ListNode *getKthFromEnd(ListNode *head, int k) {
  4. if (!head) {
  5. return head;
  6. }
  7. ListNode *fast = head;
  8. for (int i = 0; i < k; i++) {
  9. fast = fast->next;
  10. }
  11. while (fast) {
  12. fast = fast->next;
  13. head = head->next;
  14. }
  15. return head;
  16. }
  17. };

删除链表节点

237. 删除链表中的节点

  1. class Solution {
  2. public:
  3. void deleteNode(ListNode *node) {
  4. //将node 的值 赋值为 node->next的值
  5. //将node ->next 跳过下一个指向 下下一个;
  6. node->val = node->next->val;
  7. node->next = node->next->next;
  8. }
  9. };

剑指 Offer 18. 删除链表的节点

  1. class Solution {
  2. public:
  3. ListNode *deleteNode(ListNode *head, int val) {
  4. if (!head) {
  5. return head;
  6. }
  7. ListNode *dummyHead = new ListNode(-1);
  8. dummyHead->next = head;
  9. ListNode *calc = dummyHead;
  10. while (calc->next) {
  11. if (calc->next->val == val) {
  12. if (calc->next) {
  13. ListNode *node = calc->next;
  14. calc->next = node->next;
  15. node->next = nullptr;
  16. return dummyHead->next;
  17. }
  18. }
  19. calc = calc->next;
  20. }
  21. return dummyHead->next;
  22. }
  23. };
  1. class Solution {
  2. public:
  3. ListNode *deleteNode(ListNode *head, int val) {
  4. if (!head) {
  5. return head;
  6. }
  7. ListNode *dummyHead = new ListNode(-1);
  8. dummyHead->next = head;
  9. ListNode *calc = dummyHead;
  10. while (calc&&calc->next) {
  11. if (calc->next->val == val) {
  12. if (calc->next) {
  13. ListNode *node = calc->next;
  14. calc->next = node->next;
  15. node->next = nullptr;
  16. //return dummyHead->next;
  17. }
  18. }
  19. calc = calc->next;
  20. }
  21. return dummyHead->next;
  22. }
  23. };

对比下 上面两个代码的差异点;

19. 删除链表的倒数第 N 个结点

image.png

  1. ListNode *removeNthFromEnd(ListNode *head, int n) {
  2. ListNode *dummyNode = new ListNode(-1);
  3. dummyNode->next = head;
  4. ListNode *a = dummyNode;
  5. ListNode *b = dummyNode;
  6. for (int i = 0; i < n; i++) {
  7. b = b->next;
  8. }
  9. while (b->next) {
  10. a = a->next;
  11. b = b->next;
  12. }
  13. a->next = a->next->next;
  14. return dummyNode->next;
  15. }

83. 删除排序链表中的重复元素

  1. class Solution {
  2. public:
  3. //删除重复元素
  4. // 1->1->2->2->2->3
  5. ListNode *deleteDuplicates(ListNode *head) {
  6. if (!head || !head->next) {
  7. return head;
  8. }
  9. ListNode *res = head;
  10. while (res->next) {
  11. if (res->val == res->next->val) {
  12. res->next = res->next->next;
  13. } else {
  14. res = res->next;
  15. }
  16. }
  17. return head;
  18. }
  19. };

82. 删除排序链表中的重复元素 II

  1. ListNode *deleteDuplicates(ListNode *head) {
  2. if (!head) {
  3. return head;
  4. }
  5. ListNode *dummyNode = new ListNode(-1);
  6. dummyNode->next = head;
  7. ListNode *pre = dummyNode, *post = dummyNode->next;
  8. while (post) {
  9. if (post->next && post->val == post->next->val) {
  10. while (post->next && post->val == post->next->val) {
  11. post = post->next;
  12. }
  13. pre->next = post->next;
  14. post = post->next;
  15. } else {
  16. pre = pre->next;
  17. post = post->next;
  18. }
  19. }
  20. return dummyNode->next;
  21. }

面试题 02.01. 移除重复节点

  1. class Solution {
  2. public:
  3. ListNode *removeDuplicateNodes(ListNode *head) {
  4. if (!head) {
  5. return head;
  6. }
  7. unordered_set<int> bucket;
  8. ListNode *pos = head;
  9. bucket.insert(head->val);
  10. while (pos->next) { // ->next的巧妙
  11. ListNode *cur = pos->next;
  12. if (!bucket.count(cur->val)) {
  13. bucket.insert(cur->val);
  14. pos = pos->next;
  15. } else {
  16. pos->next = pos->next->next;
  17. }
  18. }
  19. pos->next = nullptr;
  20. return head;
  21. }
  22. };

203. 移除链表元素

  1. class Solution {
  2. public:
  3. ListNode *removeElements(ListNode *head, int val) {
  4. if (!head) {
  5. return head;
  6. }
  7. ListNode *dummyNode = new ListNode(-1);
  8. dummyNode->next = head;
  9. ListNode *res = dummyNode;
  10. while (res->next) {
  11. if (res->next->val == val) {
  12. res->next = res->next->next;
  13. } else {
  14. res = res->next;
  15. }
  16. }
  17. return dummyNode->next;
  18. }
  19. };

排序列表

147. 对链表进行插入排序

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode() : val(0), next(nullptr) {}
  7. * ListNode(int x) : val(x), next(nullptr) {}
  8. * ListNode(int x, ListNode *next) : val(x), next(next) {}
  9. * };
  10. */
  11. class Solution {
  12. public:
  13. ListNode *insertionSortList(ListNode *head) {
  14. if (!head) {
  15. return head;
  16. }
  17. //-1---->4---->2---->1------>3
  18. //du last cur
  19. //-1---->2---->4---->1------>3
  20. //du last cur
  21. //-1---->2---->4---->1------>3
  22. //du last cur
  23. ListNode *dummyNode = new ListNode(-1);
  24. dummyNode->next = head;
  25. ListNode *lastSorted = head, *cur = head->next;
  26. while (cur) {
  27. if (lastSorted->val <= cur->val) {
  28. lastSorted = lastSorted->next;
  29. } else {
  30. ListNode *prev = dummyNode;
  31. //使用prev指针 在last左侧 将所有比cur小的数 中给cur找合适的位置
  32. //[1]如果没有说明cur要被放到 链表头部了,因为他最小;
  33. while (prev->next->val <= cur->val) {
  34. prev = prev->next;
  35. }
  36. lastSorted->next = cur->next;
  37. cur->next = prev->next;
  38. prev->next = cur;
  39. }
  40. cur = lastSorted->next;
  41. }
  42. return dummyNode->next;
  43. }
  44. };

148. 排序链表

与上题解法一样
思考,如何获取降序的列表;

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode() : val(0), next(nullptr) {}
  7. * ListNode(int x) : val(x), next(nullptr) {}
  8. * ListNode(int x, ListNode *next) : val(x), next(next) {}
  9. * };
  10. */
  11. class Solution {
  12. public:
  13. ListNode* sortList(ListNode* head) {
  14. if (!head) {
  15. return head;
  16. }
  17. //-1---->4---->2---->1------>3
  18. //du last cur
  19. //-1---->2---->4---->1------>3
  20. //du last cur
  21. //-1---->2---->4---->1------>3
  22. //du last cur
  23. ListNode *dummyNode = new ListNode(-1);
  24. dummyNode->next = head;
  25. ListNode *lastSorted = head, *cur = head->next;
  26. while (cur) {
  27. if (lastSorted->val <= cur->val) {
  28. lastSorted = lastSorted->next;
  29. } else {
  30. ListNode *prev = dummyNode;
  31. //使用prev指针 在last左侧 将所有比cur小的数 中给cur找合适的位置
  32. //[1]如果没有说明cur要被放到 链表头部了,因为他最小;
  33. while (prev->next->val <= cur->val) {
  34. prev = prev->next;
  35. }
  36. lastSorted->next = cur->next;
  37. cur->next = prev->next;
  38. prev->next = cur;
  39. }
  40. cur = lastSorted->next;
  41. }
  42. return dummyNode->next;
  43. }
  44. };

合并链表

剑指 Offer 25. 合并两个排序的链表

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode(int x) : val(x), next(NULL) {}
  7. * };
  8. */
  9. class Solution {
  10. public:
  11. ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) {
  12. if (!l1)return l2;
  13. if (!l2)return l1;
  14. ListNode *dummyNode = new ListNode(-1);
  15. ListNode *res = dummyNode;
  16. while (l1 && l2) {
  17. if (l1->val < l2->val) {
  18. res->next = l1;
  19. l1 = l1->next;
  20. } else {
  21. res->next = l2;
  22. l2 = l2->next;
  23. }
  24. res = res->next;
  25. }
  26. while (l1) {
  27. res->next = l1;
  28. l1 = l1->next;
  29. res = res->next;
  30. }
  31. while (l2) {
  32. res->next = l2;
  33. l2 = l2->next;
  34. res = res->next;
  35. }
  36. return dummyNode->next;
  37. }
  38. };

21. 合并两个有序链表

与上面一样;

  1. ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) {
  2. if (!l1)return l2;
  3. if (!l2)return l1;
  4. ListNode *dummyNode = new ListNode(-1);
  5. ListNode *res = dummyNode;
  6. while (l1 && l2) {
  7. if (l1->val < l2->val) {
  8. res->next = l1;
  9. l1 = l1->next;
  10. } else {
  11. res->next = l2;
  12. l2 = l2->next;
  13. }
  14. res = res->next;
  15. }
  16. while (l1) {
  17. res->next = l1;
  18. res = res->next;
  19. l1 = l1->next;
  20. }
  21. while (l2) {
  22. res->next = l2;
  23. res = res->next;
  24. l2 = l2->next;
  25. }
  26. return dummyNode->next;
  27. }

1669. 合并两个链表

  1. ListNode *mergeInBetween(ListNode *list1, int a, int b, ListNode *list2) {
  2. ListNode *dummyNode = new ListNode(-1);
  3. dummyNode->next = list1;
  4. ListNode *head = dummyNode;
  5. ListNode *left = nullptr, *right = nullptr;
  6. while (a) {
  7. a--;
  8. b--;
  9. head = head->next;
  10. }
  11. left = head;
  12. while (b) {
  13. b--;
  14. head = head->next;
  15. }
  16. right = head->next;
  17. left->next = list2;
  18. while (list2->next) {
  19. list2 = list2->next;
  20. }
  21. list2->next = right;
  22. return dummyNode->next;
  23. }

23. 合并K个升序链表

image.png

解法一:循环两两合并
  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode() : val(0), next(nullptr) {}
  7. * ListNode(int x) : val(x), next(nullptr) {}
  8. * ListNode(int x, ListNode *next) : val(x), next(next) {}
  9. * };
  10. */
  11. class Solution {
  12. public:
  13. ListNode *mergeTwoList(ListNode *l1, ListNode *l2) {
  14. if (!l1)return l2;
  15. if (!l2)return l1;
  16. ListNode *dummyNode = new ListNode(-1);
  17. ListNode *res = dummyNode;
  18. while (l1 && l2) {
  19. if (l1->val < l2->val) {
  20. res->next = l1;
  21. l1 = l1->next;
  22. } else {
  23. res->next = l2;
  24. l2 = l2->next;
  25. }
  26. res = res->next;
  27. }
  28. res->next = l1 ? l1 : l2;
  29. return dummyNode->next;
  30. }
  31. ListNode *mergeKLists(vector<ListNode *> &lists) {
  32. ListNode *res = nullptr;
  33. for (int i = 0; i < lists.size(); i++) {
  34. res = mergeTwoList(res, lists[i]);
  35. }
  36. return res;
  37. }
  38. };

解法二:归并合并
  1. class Solution {
  2. public:
  3. ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) {
  4. if (!l1)return l2;
  5. if (!l2)return l1;
  6. ListNode *dummyNode = new ListNode(-1);
  7. ListNode *res = dummyNode;
  8. while (l1 && l2) {
  9. if (l1->val < l2->val) {
  10. res->next = l1;
  11. l1 = l1->next;
  12. } else {
  13. res->next = l2;
  14. l2 = l2->next;
  15. }
  16. res = res->next;
  17. }
  18. res->next = l1 ? l1 : l2;
  19. return dummyNode->next;
  20. }
  21. ListNode *merge(vector<ListNode *> &lists, int l, int r) {
  22. if (l == r)return lists[l];
  23. if (l > r)return nullptr;
  24. int mid = l + ((r - l) >> 1);
  25. return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
  26. }
  27. ListNode *mergeKLists(vector<ListNode *> &lists) {
  28. return merge(lists, 0, lists.size() - 1);
  29. }
  30. };

双链表

面试题 16.25. LRU 缓存

  1. 最近最少使用,
  2. 基于访问时间,在被访问过的元素中去除最久未使用的元素,
  3. 保证热点数据的有效性
  4. 双链表
  5. head 一直是最近被使用过的
  6. tail 代表最长未被使用的
  7. 超过阈值直接删除尾部节点
  1. struct DLinkedNode {
  2. int key, value;
  3. DLinkedNode *prev;
  4. DLinkedNode *next;
  5. DLinkedNode() : key(0), value(0), prev(nullptr), next(nullptr) {}
  6. DLinkedNode(int key, int value) : key(key), value(value), prev(nullptr), next(nullptr) {}
  7. };
  8. class LRUCache {
  9. private:
  10. unordered_map<int, DLinkedNode *> cache;
  11. DLinkedNode *head;
  12. DLinkedNode *tail;
  13. int size;
  14. int capacity;
  15. public:
  16. LRUCache(int _capacity) : capacity(_capacity), size(0) {
  17. head = new DLinkedNode();
  18. tail = new DLinkedNode();
  19. head->next = tail;
  20. tail->prev = head;
  21. }
  22. int get(int key) {
  23. if (!cache.count(key)) {
  24. return -1;
  25. }
  26. DLinkedNode *node = cache[key];
  27. moveToHead(node);
  28. return node->value;
  29. }
  30. void put(int key, int value) {
  31. if (!cache.count(key)) {
  32. DLinkedNode *node = new DLinkedNode(key, value);
  33. cache[key] = node;
  34. addToHead(node);
  35. ++size;
  36. if (size > capacity) {
  37. DLinkedNode *tail = removeTail();
  38. cache.erase(tail->key);
  39. delete tail;
  40. size--;
  41. }
  42. } else {
  43. DLinkedNode *node = cache[key];
  44. node->value = value;
  45. // 将这个节点移动到头部位置;
  46. moveToHead(node);
  47. }
  48. }
  49. //移动到头部
  50. //1.先移除这个节点
  51. //2.在头部添加
  52. //时间复杂度O(1),空间复杂度O(1)
  53. void moveToHead(DLinkedNode *node) {
  54. removeNode(node);
  55. addToHead(node);
  56. }
  57. //新节点添加到头部
  58. void addToHead(DLinkedNode *node) {
  59. node->prev = head;
  60. node->next = head->next;
  61. head->next->prev = node;
  62. head->next = node;
  63. }
  64. //移除当前节点
  65. void removeNode(DLinkedNode *node) {
  66. // 拆断 双向链表中的双向;
  67. node->prev->next = node->next;
  68. node->next->prev = node->prev;
  69. }
  70. //移除尾部节点 并返回节点
  71. DLinkedNode *removeTail() {
  72. DLinkedNode *node = tail->prev;
  73. removeNode(node);
  74. return node;
  75. }
  76. };

460. LFU 缓存

  1. LFU最近最不常用,基于访问次数,去除命中次数最少的元素,保证高频数据有效性
  2. struct Node {
  3. int cnt, time, key, value;
  4. Node() {}
  5. Node(int _cnt, int _time, int _key, int _value) : cnt(_cnt), time(_time), key(_key), value(_value) {}
  6. bool operator<(const Node &ht) const {
  7. return cnt == ht.cnt ? time < ht.time : cnt < ht.cnt;
  8. }
  9. };
  10. class LFUCache {
  11. int capacity; //缓存容量
  12. int time;//最新的时间点(用int大小代替),全局
  13. unordered_map<int, Node> key_table;
  14. set<Node> sortTree;//用于做结构体内部自动排序
  15. public:
  16. LFUCache(int _capacity) {
  17. this->capacity = _capacity;
  18. time = 0;
  19. key_table.clear();
  20. sortTree.clear();
  21. }
  22. int get(int key) {
  23. if (capacity == 0) return -1;
  24. auto it = key_table.find(key);
  25. if (it == key_table.end()) {
  26. return -1;
  27. }
  28. Node cache = it->second;
  29. sortTree.erase(cache);
  30. cache.cnt += 1;
  31. cache.time = ++time;
  32. sortTree.insert(cache);
  33. key_table[key] = cache;
  34. return cache.value;
  35. }
  36. void put(int key, int value) {
  37. if (capacity == 0)return;
  38. auto it = key_table.find(key);
  39. if (it == key_table.end()) {
  40. //达到容量阈值
  41. if (key_table.size() == capacity) {
  42. auto first = sortTree.begin();
  43. key_table.erase(first->key);
  44. sortTree.erase(first);
  45. }
  46. //如果没有到阈值,构建新缓存
  47. Node cache = Node(1, ++time, key, value);
  48. key_table.insert({key, cache});
  49. sortTree.insert(cache);
  50. } else {
  51. Node cache = it->second;
  52. sortTree.erase(cache);
  53. cache.cnt += 1;
  54. cache.time = ++time;
  55. cache.value = value;
  56. sortTree.insert(cache);
  57. key_table[key] = cache;
  58. }
  59. }
  60. };