当前位置: 首页 > news >正文

Leetcode链表问题汇总

目录

      • [2. 两数相加](https://leetcode.cn/problems/add-two-numbers/)
      • [206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/)
      • [206. 反转链表 II](https://leetcode.cn/problems/reverse-linked-list-ii/)
      • [19. 删除链表的倒数第 N 个结点](https://leetcode.cn/problems/remove-nth-node-from-end-of-list/)
      • [21. 合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists/)
      • [61. 旋转链表](https://leetcode.cn/problems/rotate-list/)
      • [82. 删除排序链表中的重复元素 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/)
      • [83. 删除排序链表中的重复元素重复元素](https://leetcode.cn/problems/remove-duplicates-from-sorted-list/)
      • [141. 环形链表](https://leetcode.cn/problems/linked-list-cycle/)
      • [142. 环形链表 II](https://leetcode.cn/problems/linked-list-cycle-ii/)
      • [143. 重排链表](https://leetcode.cn/problems/reorder-list/)

2. 两数相加

比较简单的题目,头结点标示的个位数字,因此直接模拟就可以了。注意链表相关的题目可以添加一个虚拟头节点,用来简化一些边界情况的处理。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {ListNode* res = new ListNode(-1);ListNode* cur = res;int carry = 0; //进位标示while (l1 || l2) {int v1 = l1 ? l1 -> val : 0;int v2 = l2 ? l2 -> val : 0;int sum = v1 + v2 + carry;carry = sum / 10;cur -> next = new ListNode(sum % 10);cur = cur -> next;if (l1) l1 = l1 -> next;if (l2) l2 = l2 -> next;}if (carry) cur -> next = new ListNode(1);return res -> next;}
};

206. 反转链表

翻转即将所有节点的next指针指向前驱节点。由于是单链表,我们在迭代时不能直接找到前驱节点,所以我们需要一个额外的指针保存前驱节点。同时在改变当前节点的next指针前,不要忘记保存它的后继节点。
其实相当于头插法!

class Solution {
public:ListNode* reverseList(ListNode* head) {ListNode* prev = nullptr;ListNode* cur = head;while (cur) {ListNode* nxt = cur -> next;cur -> next = prev;prev = cur;cur = nxt;}return prev;}
};

还有一种递归的写法:
首先我们先考虑 reverseList 函数能做什么,它可以翻转一个链表,并返回新链表的头节点,也就是原链表的尾节点。
所以我们可以先递归处理 reverseList(head->next),这样我们可以将以head->next为头节点的链表翻转,并得到原链表的尾节点tail,此时head->next是新链表的尾节点,我们令它的next指针指向head,并将head->next指向空即可将整个链表翻转,且新链表的头节点是tail。

class Solution {
public:ListNode* reverseList(ListNode* head) {if (!head || !head->next) return head;ListNode *tail = reverseList(head->next);head->next->next = head;head->next = nullptr;return tail;}
};

206. 反转链表 II

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* reverseBetween(ListNode* head, int left, int right) {ListNode* dummy = new ListNode(-1); // 建立一个虚拟头节点,因为有可能left==1,避免处理边界情况dummy -> next = head;auto a = dummy;for (int i = 0; i < left - 1; i++) a = a -> next; //找到left的前一个节点auto b = a -> next, c = b -> next;//接下来是反转链表的逻辑,要做right - left次for (int i = 0; i < right - left; i++) {auto d = c -> next;c -> next = b;b = c, c = d;}//两头的指针搞正确a -> next -> next = c;a -> next = b;return dummy -> next;}
};

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

找到前面的那个点,改掉指针即可。

class Solution {
public:ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode* dummy = new ListNode(-1);dummy -> next = head;// sz: 包含虚拟头结点的整个链表的长度int sz = 0;for (auto p = dummy; p; p = p -> next) sz++;// 倒数第N个节点,也就是正数的(sz+1-n)个点.// 要删除这个点,要先到它前面的那个点,也就是第(sz-n)个点,从dummy开始跳,需要跳(sz-n-1)步auto p = dummy;for (int i = 0; i < sz - n - 1; i++) p = p -> next;p -> next = p -> next -> next;return dummy -> next;}
};

21. 合并两个有序链表

判断大小,直接模拟即可,注意代码的简洁性。

class Solution {
public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {ListNode* dummy=  new ListNode(-1);ListNode* tail = dummy;while (l1 && l2) {if (l1 -> val < l2 -> val) tail = tail -> next = l1, l1 = l1 -> next;else tail = tail -> next = l2, l2 = l2 -> next;}if (l1) tail -> next = l1;if (l2) tail -> next = l2;return dummy -> next;}
};

61. 旋转链表

相当于把后面一部分的链表拼接到前面

class Solution {
public:ListNode* rotateRight(ListNode* head, int k) {if (!head) return head;int sz = 0; //链表长度ListNode* tail; //当前链表的尾节点for (auto p = head; p; p = p -> next) {tail = p;sz++;}k %= sz;if (!k) return head;auto p = head;//找到前半部分的最后的元素for (int i = 0; i < sz - k - 1; i++) p = p -> next;//把后半部分拼到前面即可//1. 前半部分的尾结点的next指向空//2. 后半部分的尾结点的next指向链表的头结点tail -> next = head;head = p -> next; // 这个是最新的头结点p -> next = nullptr;return head;}
};

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

类似于双指针,判断一段相等值的个数是只有一个,还是至少两个,来选择不同的策略。注意看代码里的条件判断的部分。

class Solution {
public:ListNode* deleteDuplicates(ListNode* head) {auto dummy = new ListNode(-1);dummy -> next = head;auto p = dummy;while (p -> next) {auto first = p -> next;auto end = first -> next;// 让end走到和first不等的节点while (end && end -> val == first -> val) end = end -> next; // 说明相等这一段只有一个if (first -> next == end) p = p -> next;// 至少有两个,那么跳过这一段else p -> next = end;}return dummy -> next;}
};

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

其实把上面题的else里面改一下就可以了

class Solution {
public:ListNode* deleteDuplicates(ListNode* head) {auto dummy = new ListNode(-1);dummy -> next = head;auto p = dummy;while (p -> next) {auto first = p -> next;auto end = first -> next;while (end && end -> val == first -> val) end = end -> next; if (first -> next == end) p = p -> next;else p -> next -> next = end;}return dummy -> next;}
};

当然也有更简单的写法,思路就是判断一下枚举到的值和当前的值是否相等,只保留不相等的节点

class Solution {
public:ListNode* deleteDuplicates(ListNode* head) {if (!head) return head;auto cur = head;for (auto p = head -> next; p; p = p -> next) {if (p -> val != cur -> val) cur = cur -> next = p;}cur -> next = nullptr;return head;}
};

141. 环形链表

用两个指针从头开始扫描,第一个指针每次走一步,第二个指针每次走两步。如果走到 null,说明不存在环;否则如果两个指针相遇,则说明存在环。
原因:
假设链表存在环,则当第一个指针走到环入口时,第二个指针已经走到环上的某个位置,距离环入口还差 x 步。由于第二个指针每次比第一个指针多走一步,所以第一个指针再走 x步,两个指针就相遇了。
复杂度分析,由于慢指针走的总步数小于链表总长度,复杂度为 O ( N ) O(N) O(N).

class Solution {
public:bool hasCycle(ListNode *head) {if (!head || !head -> next) return false;ListNode* slow = head;ListNode* fast = head -> next;while (slow && fast) {if (slow == fast) return true;slow = slow -> next;fast = fast -> next;if (fast) fast = fast -> next;}return false;}
};

142. 环形链表 II

143. 重排链表

http://www.lryc.cn/news/204723.html

相关文章:

  • 基于卷的磁盘扫描算法设计
  • 计算机组成原理-存储器概念
  • 力扣刷题 day54:10-24
  • Java基础篇 | Java8流式编程
  • SolidworksSimulation完成对压力容器的强度分析
  • 【C++】继承 ⑨ ( 继承中成员变量同名的处理方案 )
  • Python报错:‘EagerTensor‘ object has no attribute ‘reshape‘
  • docker-compose手册
  • 【珠峰 WEB 前端架构师课程】学习笔记 100 篇(完结)
  • Java线程中sleep()、wait()、yield()、join()方法的使用
  • 【机器学习】数据均衡学习笔记
  • 【软件教程】如何用C++交叉编译出能在Android运行的ELF程序或so动态库
  • 进阶JAVA篇- Map 系列集合的遍历方法与常用API
  • Auth.js:多合一身份验证解决方案 | 开源日报 No.60
  • SpringBoot整合Activiti7——任务监听器(七)
  • 电解电容寿命与哪些因素有关?
  • Opencv-图像插值与LUT查找表
  • 我为什么写博客?写博客给我带来了什么?
  • jdk11的HttpClient
  • Redis的优势
  • C++ string 类的其他操作
  • structs2 重构成SpringBoot架构
  • 【MATLAB源码-第56期】基于WOA白鲸优化算法和PSO粒子群优化算法的三维路径规划对比。
  • 【WinForm详细教程一】WinForm中的窗体、Label、TextBox及Button控件、RadioButton和CheckBox、ListBox
  • 【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar
  • PureFlash云原生存储部署方法
  • SqueezeNet 一维,二维网络复现 pytorch 小白易懂版
  • Java 数据结构
  • python sqlalchemy(ORM)- 02 表关系
  • Http长连接同一个socket多个请求和响应如何保证一一对应?