leetcode
leetcode 51 ~ 100
分隔链表

分隔链表

难度:

标签:

题目描述

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。

你应当 保留 两个分区中每个节点的初始相对位置。

 

示例 1:

输入:head = [1,4,3,2,5,2], x = 3
输出:[1,2,2,4,3,5]

示例 2:

输入:head = [2,1], x = 2
输出:[1,2]

 

提示:

  • 链表中节点的数目在范围 [0, 200]
  • -100 <= Node.val <= 100
  • -200 <= x <= 200

代码结果

运行时间: 44 ms, 内存: 15 MB


// Java Stream Solution
// 注意:Java的Stream不适用于链表操作,因此此方法使用常规Java代码。
// 思路:与普通Java解法相同,无法使用Stream进行链表操作。
class ListNode {
    int val;
    ListNode next;
    ListNode(int val) { this.val = val; }
}
 
class Solution {
    public ListNode partition(ListNode head, int x) {
        ListNode smallerHead = new ListNode(0);
        ListNode greaterHead = new ListNode(0);
        ListNode smaller = smallerHead, greater = greaterHead;
        while (head != null) {
            if (head.val < x) {
                smaller.next = head;
                smaller = smaller.next;
            } else {
                greater.next = head;
                greater = greater.next;
            }
            head = head.next;
        }
        greater.next = null;
        smaller.next = greaterHead.next;
        return smallerHead.next;
    }
}

解释

方法:

该题解的思路是将原链表拆分为两个子链表,一个存储所有小于x的节点,一个存储所有大于等于x的节点。创建两个虚拟头节点dummy1和dummy2,分别指向两个子链表。遍历原链表,将每个节点按值的大小关系插入到对应的子链表末尾。最后,将大于等于x的子链表接到小于x的子链表的末尾,并返回小于x子链表的头节点。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
在题解中,如果链表已经是空,直接返回head合适吗?这是否意味着应该有一个特殊处理或返回值以区分空链表和处理后的链表相同的情况?
在题解中,如果链表已经为空,直接返回head是合适的。这是因为处理空链表的结果自然应该是一个空链表,无需进一步处理。直接返回head实际上返回的是null,这恰当地表示了处理后的链表是空的。这种方法清晰地表明了链表为空的情况,并且不需要额外的特殊处理或返回值来区分,因为返回的null已经足够表明链表为空。
🦆
为什么在连接两个子链表之前,需要将大于等于x的子链表的末尾指向None,这一步具体是为了解决什么问题?
在连接两个子链表之前,将大于等于x的子链表的末尾指向None是必要的,以避免引入可能的循环引用。当原链表中的节点被重新分配到两个子链表中时,最后一个大于等于x的节点的next指针可能仍然指向一个小于x的节点,形成一个循环。将此节点的next指针设置为None确保了所有节点都正确地结束,使得子链表成为一个正确的单向序列,从而可以安全地将两个子链表连接起来。
🦆
你是如何确保在将小于x的节点和大于等于x的节点分开时,他们的相对顺序保持不变的?
在题解中,通过维护两个指针p1和p2分别指向两个虚拟头节点dummy1和dummy2,然后逐个遍历原链表中的节点,根据节点的值将它们直接链接到相应子链表的末尾来保持节点的相对顺序。这种方法确保了节点插入到子链表中的顺序与它们在原链表中的顺序相同,因此小于x的节点和大于等于x的节点在各自的子链表中保持了原有的相对顺序。
🦆
题解中提到将大于等于x的子链表接到小于x的子链表末尾,这种操作是否可能导致原链表中的循环引用?如果是,应该如何避免?
在连接两个子链表之前,因为已经将大于等于x的子链表的末尾节点的next指针设置为None,所以这种操作不会导致原链表中的循环引用。这一步骤是关键的,因为它确保了原链表的末端不会意外地连接回链表的某个中间节点。只要确保这一点,就能安全地将大于等于x的子链表接到小于x的子链表的末尾,而不会引起循环引用的问题。

相关问题