文章目录
- 写在前面
- Tag
- 题目来源
- 解题思路
- 方法一:模拟
- 写在最后
写在前面
本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更……
专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结构等内容进行回顾与总结,文章结构大致如下,部分内容会有增删:
- Tag:介绍本题牵涉到的知识点、数据结构;
- 题目来源:贴上题目的链接,方便大家查找题目并完成练习;
- 题目解读:复述题目(确保自己真的理解题目意思),并强调一些题目重点信息;
- 解题思路:介绍一些解题思路,每种解题思路包括思路讲解、实现代码以及复杂度分析;
- 知识回忆:针对今天介绍的题目中的重点内容、数据结构进行回顾总结。
Tag
【链表】【模拟】
题目来源
86. 分隔链表
解题思路
方法一:模拟
我们只需要维护两个链表 small
和 large
即可,前者用来按顺序存储所有小于 x
的节点,后者用来按顺序存储所有大于等于 x
的节点。
为了实现上述思路,我们分别定义了两个链表的两个指针,small
链表的头结点 sH
、尾节点 sT
,large
链表的头结点 eAndgH
、尾节点 eAndgT
。
从原链表的头结点 head
开始遍历,直至结束,记当前遍历的节点为 cur
:
- 首先记录当前节点的下一个节点
next
; - 将当前的节点
cur
指向空节点; - 接着将
cur
的值与x
进行比较:- 如果小于
x
,则更新到small
节点中,主要如果此时的sH
为空,需要利用氮当前节点初始化sH
,否则直接将cur
加在sH
后面并更新sT = cur
; - 类似的对于
cur->val >= x
的情况,也有类似操作
- 如果小于
- 最后更新
cur = next
。
最后,遍历完毕原链表后,将两段链表拼接起来。
返回答案时,如果 sT == nullptr
,说明 small
链表为空,直接返回 large
链表的头结点 eAndgH
即可;否则返回 small
链表的头结点。
代码
/**
* 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* partition(ListNode* head, int x) {
ListNode* sH = nullptr, * sT = nullptr;
ListNode* eAndgH = nullptr, * eAndgT = nullptr;
ListNode* next = nullptr;
while(head != nullptr) { // 使用 head 作为当前的节点
next = head->next;
head->next = nullptr;
if(head->val < x) {
if(sH == nullptr) {
sH = head;
sT = head;
}else {
sT->next = head;
sT = head;
}
}
else {
if(eAndgH == nullptr) {
eAndgH = head;
eAndgT = head;
}else {
eAndgT->next = head;
eAndgT = head;
}
}
head = next;
}
// 重新链接
if(sT != nullptr) {
sT->next = eAndgH;
}
return sT == nullptr ? eAndgH : sH;
}
};
复杂度分析
时间复杂度: O ( n ) O(n) O(n), n n n 为原链表的长度。
空间复杂度: O ( 1 ) O(1) O(1)。
写在最后
如果您发现文章有任何错误或者对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。
如果大家有更优的时间、空间复杂度的方法,欢迎评论区交流。
最后,感谢您的阅读,如果有所收获的话可以给我点一个 👍 哦。