「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战」
分隔链表 Partition list
LeetCode传送门86. 分隔链表
题目
给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
你应当 保留 两个分区中每个节点的初始相对位置。
Given the head of a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.
You should preserve the original relative order of the nodes in each of the two partitions.
Example:
图示第一个例子

Input: head = [1,4,3,2,5,2], x = 3
Output: [1,2,2,4,3,5]
Input: head = [2,1], x = 2
Output: [1,2]
Constraints:
- The number of nodes in the list is in the range [0, 200].
- -100 <= Node.val <= 100
- -200 <= x <= 200
思考线
解题思路
来分析一下这道题,给我们一个链表,和一个值x,让我们把小于x的元素放到左边,大于等于x的元素放到右边,并且保证位置的相对性。
我们一起来找这道题的核心点
- 让我们把小于
x的元素放到左边,大于等于x的元素放到右边 - 保证位置的相对性。
关于第一个核心点,我们可以遍历链表,然后如果遇到比x小的元素我们把它放到链表的头部,如果遇到>=x的元素我们不用处理,只需要让list = list.next即可。这样一来,当遍历完成时,我们就能保证左边的全部都是比x小的,而右边的都比>=x的。这样一来,我们就解决完了第一个问题。
再看一下第二个核心点,保证位置的相对性,我们在做上面的操作时,只能保证右边>=x的部分的位置的相对性,而对于左边位置的相对性却没有办法保证。
那么怎么办才能保证左边元素的相对性呢?
我们在这里先设置一个虚拟头结点dummyHead,然后设置一个 pre指针,指向dummyHead,然后每次如果出现节点元素小于x时,我们就把该节点的元素node塞到pre的后面,最后执行pre = pre.next即可。这样一来我们的左边节点也是有序的了。那这道题的核心点也就完成了。
值得注意的点
在我们执行把比x小的元素放到左边的时候,我们要判断当前的list.next 和 pre.next是否相等,因为若刚开始头部比x小的话,list是和pre相同的,而此时,若我们执行放到左边的操作不但多余,而且会造成解析混乱从而导致结果不准确。
好了我们的逻辑分析完毕了,我们一起来看看如何实现吧
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function partition(head: ListNode | null, x: number): ListNode | null {
// 先设置一个虚拟头结点
const dummyHead = new ListNode(-111);
dummyHead.next = head;
let pre = dummyHead; // 为了保证左边元素的相对位置,我们用pre来定位应该把下一个比x小的元素插入到pre的后面
let list = dummyHead; // 设置变量list,后面用于遍历链表
while(list?.next) {
if(list.next.val >= x) { // 如果大于等于x,我们不用管,只需要把元素指向下一个即可
list = list.next;
} else { // 如果当前元素小于x
if(list.next === pre.next) { // 排除从头部开始就一直是小元素的情况
pre = pre.next;
list = list.next;
continue;
}
// 先把node从右边取出来
const node = list.next;
list.next = node.next;
// 再把node 插入 pre后面
const preNode = pre.next;
pre.next = node;
node.next = preNode;
pre = pre.next; // 把pre向后挪动一位,以便保证下一个插入元素位置的相对性
}
}
return dummyHead.next;
};
时间复杂度
O(n): 其中n为链表的长度。
这就是我对本题的解法,如果有疑问或者更好的解答方式,欢迎留言互动。