链表

套路总结

1.多个指针 移动

2.虚假链表头:凡是有可能删除头节点的都创建一个虚拟头节点,代码可以少一些判断(需要用到首部前一个元素的时候就加虚拟头指针)

3.快慢指针

如leetcode142 快慢指针找链表环的起点

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

题目要求:只扫描一遍

删除链表,肯定要找到被删节点的前一个节点

1.找到倒数第n个节点的前一个节点(倒数第n+1)

2.双指针

first指针指向第k个,second头指针指向虚假头节点,两个指针一起移动,当first指针指向最后一个节点的时候(first下一个节点为NULL),就说明second到达了倒数第k个节点

3.删除即可 second ->next = second->next->next

  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* removeNthFromEnd(ListNode* head, int n) {
  12. auto dummy = new ListNode(-1);
  13. dummy->next = head;
  14. auto first = dummy;
  15. auto second = dummy;
  16. while(n--) first = first->next;
  17. while(first->next != NULL){
  18. second = second->next;
  19. first = first->next;
  20. }
  21. second->next = second->next->next;
  22. return dummy->next;
  23. }
  24. };

237. 删除链表中的节点

例如,给定node指向5这个点,删除5这个点

真正意义删除要知道被删除节点的上一个点

假装删除,把这个点的值伪装成下一个点的值,把下一个点删掉即可

  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. void deleteNode(ListNode* node) {
  12. if(node->next){
  13. node->val = node->next->val;
  14. node->next = node->next->next;
  15. }
  16. return;
  17. }
  18. };

C++语法把node两个属性的值都一起替换为下一个节点的属性

  1. *(node) = *(node->next);

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

  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* deleteDuplicates(ListNode* head) {
  12. auto *first = head;
  13. while(first && first->next){
  14. if(first->val == first->next->val){
  15. first->next = first->next->next;
  16. }else{
  17. first = first->next;
  18. //这里first可能移动到了空 所以要判断first是否空
  19. }
  20. }
  21. return head;
  22. }
  23. };

82. 删除排序链表中的重复元素 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* deleteDuplicates(ListNode* head) {
  12. auto dummy = new ListNode(-1);
  13. dummy->next = head;
  14. auto pre = dummy,cur = pre->next;
  15. int cnt = 0;
  16. while(pre && cur){
  17. cnt = 0;
  18. auto nxt = cur->next;
  19. while(nxt && nxt->val == cur->val) {
  20. cnt++;
  21. nxt = nxt->next;
  22. }
  23. if(cnt >= 1){
  24. pre->next = nxt;
  25. cur = pre->next;
  26. }else{
  27. pre = pre->next;
  28. cur = pre->next;
  29. }
  30. }
  31. return dummy->next;
  32. }
  33. };

61. 旋转链表

两个指针,距离为k

(不需要用到虚拟头节点,头节点会改变时用到)

之后让first->next指向开头head,再让head指向现在的头(second->next)!

再让second->next指向空

  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* rotateRight(ListNode* head, int k) {
  12. if(!head) return NULL;
  13. int n = 0;
  14. for(auto p = head;p;p=p->next) n++;
  15. k %= n;
  16. auto first = head,second = head;
  17. while(k--) first = first->next;
  18. while(first->next){
  19. first=first->next;
  20. second=second->next;
  21. }
  22. first->next = head;
  23. head = second->next;
  24. second->next = NULL;
  25. return head;
  26. }
  27. };

24. 两两交换链表中的节点

1.建立虚拟头节点,因为头节点可能会改变

2.三个指针

  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* swapPairs(ListNode* head) {
  12. auto dummy = new ListNode(-1);
  13. dummy->next = head;
  14. for(auto p = dummy;p->next && p->next->next;){
  15. auto a = p->next,b = a->next;
  16. p->next = b;
  17. a->next = b->next;
  18. b->next = a;
  19. p = a; //指向下一个新的两对前的最后一个点
  20. }
  21. return dummy->next;
  22. }
  23. };

206. 反转链表

两个翻转指针a,b;一个保留指针c保留b后面的链防止被删除,不需要虚拟头节点因为不需要用到首部前一个

分三步

  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* reverseList(ListNode* head) {
  12. if(!head) return NULL;
  13. auto a = head,b = head->next;
  14. while(b){
  15. auto c = b->next;
  16. b->next = a;
  17. a = b;
  18. b = c;
  19. }
  20. head->next = NULL;//原来头是原来的第一节点 现在的最后一个节点所以指向空
  21. head = a;
  22. return head;
  23. }
  24. };

92. 反转链表 II

1.因为头节点会发生变化,设置虚拟头节点

2.a指针移动到翻转前一个点,b指针移动第一个翻转的点,d指针移动到最后一个翻转的点。c指针指向最后一个翻转的点的下一个点。然后翻转b~d之间的点和206题一样

3.连接a->d,b->c

  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* reverseBetween(ListNode* head, int m, int n) {
  12. if(m == n) return head;
  13. auto dummy = new ListNode(-1); //虚拟头节点
  14. dummy->next = head;
  15. //找到a和d
  16. auto a = dummy,d = dummy;
  17. for(int i=0;i<m-1;i++) {
  18. a = a->next;//不设置虚拟头节点的话,如果n=1就找不到了a
  19. }
  20. for(int i=0;i<n;i++) d = d->next;
  21. //找到b和c
  22. auto b = a->next, c = d->next;
  23. //翻转b和d之间的数字
  24. for(auto first = b->next,second = b; first != c;){
  25. auto third = first->next;
  26. first->next = second;
  27. second = first,first = third;
  28. }
  29. //连接
  30. b->next = c;
  31. a->next = d;
  32. return dummy->next;
  33. }
  34. };

160. 相交链表

相遇:当指针p和指针q走的路程相等时相遇

考虑都走a+b+c的倍数,肯定会相遇

  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 *getIntersectionNode(ListNode *headA, ListNode *headB) {
  12. auto tempHeadA = headA;
  13. auto tempHeadB = headB;
  14. while(tempHeadA != tempHeadB){
  15. if(tempHeadA) tempHeadA = tempHeadA->next;
  16. else tempHeadA = headB;
  17. if(tempHeadB) tempHeadB = tempHeadB->next;
  18. else tempHeadB = headA;
  19. }
  20. return tempHeadB;
  21. }
  22. };

142. 环形链表 II

快慢指针

1.快指针慢指针从head头部出发,fast快指针每次走两步,slow慢指针每次走一步直到相遇。

2.把其中一个指针移动到head头部,快慢指针再每次走一步直到相遇,相遇点即为答案;

证明:利用快指针走动过的是慢指针的二倍,假设环起点坐标为x,第一次相遇点距离换起点距离为y。

可列公式2×(x+n1×c+y)=x+y+n2×c ,化简得x+y=(n2-n1)×c。

大白话说就是:非环部分的长度+环起点到相遇点之间的长度就是环的整数倍。

即x+y为环的整数倍

那么第一次相遇时我们现在距离环起点为y,所以只要再走x就到环起点了

再走x的话就让一个指针从head走,另一个从第一次相遇点走,每次都走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 *detectCycle(ListNode *head) {
  12. auto fast = head,slow = head;
  13. while(fast && fast->next){
  14. fast = fast->next;
  15. fast = fast->next; //快指针移动两次
  16. slow = slow->next; //慢指针移动1次
  17. if(fast == slow){ //当快慢指针相遇时退出
  18. break;
  19. }
  20. }
  21. if(fast==NULL || fast->next == NULL)
  22. return NULL;
  23. else{
  24. slow = head; //让其中一个指针移动到头部
  25. while(fast != slow){ //再走到相遇点即可
  26. fast = fast->next;
  27. slow = slow->next;
  28. }
  29. return slow;
  30. }
  31. }
  32. };

148. 排序链表

要求空间常数,时间O(nlogn)

因为快排用到递归(栈),空间为logn;递归版归并空间消耗大;所以用迭代版归并

自底向上代码写法:先枚举长度为2,分成一半,左右归并;再枚举长度为4...

  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* sortList(ListNode* head) {
  12. int n = 0;
  13. for(auto p = head; p ; p = p -> next) n++;
  14. auto dummy = new ListNode(-1);
  15. dummy->next = head;
  16. for(int i=1; i<n ; i*=2){ //枚举每一段的一半长
  17. auto cur = dummy;
  18. for(int j=0; j+i<n ; j+=i*2){
  19. auto left = cur->next; //左半段边界指针
  20. auto right = cur->next; //右半段边界指针
  21. for(int k=0;k<i;k++) right = right->next;
  22. int l = 0,r = 0;
  23. while(l < i && r < i && right){ //归并比较左右哪个大
  24. if(left->val <= right-> val){
  25. cur->next = left;
  26. cur = left;
  27. left = left->next;
  28. l++;
  29. }else{
  30. cur->next = right;
  31. cur = right;
  32. right = right->next;
  33. r++;
  34. }
  35. }
  36. //一个先到了末尾 所以要拼接另一端的剩余部分
  37. while(l < i){
  38. cur->next = left;
  39. cur = left;
  40. left = left->next;
  41. l++;
  42. }
  43. while(r < i && right){
  44. cur->next = right;
  45. cur = right;
  46. right = right->next;
  47. r++;
  48. }
  49. cur->next = right; //拼接下一段 这里的right最终指向了下一段的left
  50. }
  51. }
  52. return dummy->next;
  53. }
  54. };

21. 合并两个有序链表

(线性合并) O(n)O(n)

1.新建头部的保护结点 dummy,设置 cur 指针指向 dummy。

2.如果p的值比q小,就将cur->next = p,否则让cur -> next = q (选小的先连接)

循环以上步骤直到 l1l1 或 l2l2 为空。

3.将剩余的 p或 q连 接到 cur 指针后边。

  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. auto dummmy = new ListNode(-1);
  13. auto cur = dummmy;
  14. auto p = l1,q = l2;
  15. //选小的优先
  16. while(p && q){
  17. if(p->val <= q->val){
  18. cur->next = p;
  19. cur = p;
  20. p = p->next;
  21. }else{
  22. cur->next = q;
  23. cur = q;
  24. q = q->next;
  25. }
  26. }
  27. //加入剩余
  28. while(p){
  29. cur->next = p;
  30. p = p->next;
  31. }
  32. while(q){
  33. cur->next = q;
  34. q = q->next;
  35. }
  36. // cur->next = (p != NULL ? p : q);
  37. return dummmy->next;
  38. }
  39. };

LeetCode链表专题的更多相关文章

  1. LeetCode 单链表专题 (一)

    目录 LeetCode 单链表专题 <c++> \([2]\) Add Two Numbers \([92]\) Reverse Linked List II \([86]\) Parti ...

  2. LeetCode:链表专题

    链表专题 参考了力扣加加对与链表专题的讲解,刷了些 leetcode 题,在此做一些记录,不然没几天就没印象了 出处:力扣加加-链表专题 总结 leetcode 中对于链表的定义 // 定义方式1: ...

  3. LeetCode刷题 链表专题

    链表专题 链表题目的一般做法 单链表的结构类型 删除节点 方法一 方法二 增加节点 LeedCode实战 LC19.删除链表的倒数第N个结点 解法思路 LC24.两两交换链表中的节点 解法思路 LC6 ...

  4. LeetCode 字符串专题(一)

    目录 LeetCode 字符串专题 <c++> \([5]\) Longest Palindromic Substring \([28]\) Implement strStr() [\(4 ...

  5. [LeetCode] [链表] 相关题目总结

    刷完了LeetCode链表相关的经典题目,总结一下用到的技巧: 技巧 哑节点--哑节点可以将很多特殊case(比如:NULL或者单节点问题)转化为一般case进行统一处理,这样代码实现更加简洁,优雅 ...

  6. LeetCode树专题

    LeetCode树专题 98. 验证二叉搜索树 二叉搜索树,每个结点的值都有一个范围 /** * Definition for a binary tree node. * struct TreeNod ...

  7. Leetcode链表

    Leetcode链表 一.闲聊 边学边刷的--慢慢写慢慢更 二.题目 1.移除链表元素 题干: 思路: 删除链表节点,就多了一个判断等值. 由于是单向链表,所以要删除节点时要找到目标节点的上一个节点, ...

  8. [LeetCode 总结帖]: 链表专题

    链表在笔试面试中都是出镜率极高的一种数据结构. 由于链表具有结构简单,代码量较少,变化多,可以较为全面的考察应聘者的逻辑思考能力以及应变能力的特点,而备受面试官青睐. 在本节中,我将Leetcode中 ...

  9. [LeetCode] 链表反转相关题目

    暂时接触到LeetCode上与链表反转相关的题目一共有3道,在这篇博文里面总结一下.首先要讲一下我一开始思考的误区:链表的反转,不是改变节点的位置,而是改变每一个节点next指针的指向. 下面直接看看 ...

随机推荐

  1. 通用Mapper使用

    通用Mapper介绍 产生背景 使用Mybatis的开发者大多会因为繁多的XML映射配置而头痛不已

  2. 初学者的Pygame安装教程

    最近在自学python,在看完了些基础知识之后,准备写个小项目[外星人入侵],这个项目需要安装pygame. 所以就在网上找到了两个下载地址https://bitbucket.org/pygame/p ...

  3. Spark-BlockManager

    简单说明 BlockManager是管理整个Spark运行时数据的读写,包含数据存储本身,在数据存储的基础之上进行数据读写.由于Spark是分布式的,所有BlockManager也是分布式的,Bloc ...

  4. Tidyverse|数据列的分分合合,爱恨情仇

    Tidyverse|数据列的分分合合,爱恨情仇 本文首发于“生信补给站”Tidyverse|数据列的分分合合,一分多,多合一 TCGA数据挖掘可做很多分析,前期数据“清洗”费时费力但很需要. 比如基因 ...

  5. swoole学习--登录模块

    使用swoole+thinkphp6.0+redis 结合开发的登录模块,做完之后有几点感悟: 1.不要相信任务数据,包括请求的外部接口,特别是超时者部分,尽可能的交给task完成. 2.原来可以在入 ...

  6. vSphere可用性之三准备实验环境

    第三章 准备实验环境 在上篇内容中,讲述了进行VMware HA实验所必需的软硬件条件.接下来将使用这些来搭建实验环境.主要内容为依据拓扑图安装ESX主机系统.ISCSI存储系统. 此次实验环境的建置 ...

  7. ACM-ICPC 2019 山东省省赛D Game on a Graph

    Game on a Graph Time Limit: 1 Second Memory Limit: 65536 KB There are people playing a game on a con ...

  8. 图论--最短路--Floyd(含路径输出)

    #include<bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define maxn 1005 int D[ma ...

  9. python(open 文件)

    一.open 文件 1.open('file','mode')打开一个文件 file 要打开的文件名,需加路径(除非是在当前目录) mode 文件打开的模式 需要手动关闭 close 2.with o ...

  10. 最新Idea超实用告别996插件,都是免费

    Idea告别996插件 在IntelliJ IDEA中,秉着IDEA自带能实现的快捷方式就不用插件的原则,少用些插件,运行性能也提升一些,虽然很少,哈哈.分享下我个人常用的插件,希望对大家有些帮助.插 ...