[路飞]_每天刷leetcode_53( 分隔链表 Partition list)

219 阅读3分钟

「这是我参与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的元素放到右边,并且保证位置的相对性。

我们一起来找这道题的核心点

  1. 让我们把小于x的元素放到左边,大于等于x的元素放到右边
  2. 保证位置的相对性。

关于第一个核心点,我们可以遍历链表,然后如果遇到比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为链表的长度。

这就是我对本题的解法,如果有疑问或者更好的解答方式,欢迎留言互动。