标题:分隔链表
出处:86. 分隔链表
5 级
给你一个链表的头结点 head \texttt{head} head 和一个特定值 x \texttt{x} x,请你对链表进行分隔,使得所有小于 x \texttt{x} x 的结点都出现在大于或等于 x \texttt{x} x 的结点之前。
你应当保留两个分区中每个结点的初始相对位置。
示例 1:
输入: head = [1,4,3,2,5,2], x = 3 \texttt{head = [1,4,3,2,5,2], x = 3} head = [1,4,3,2,5,2], x = 3
输出: [1,2,2,4,3,5] \texttt{[1,2,2,4,3,5]} [1,2,2,4,3,5]
示例 2:
输入: head = [2,1], x = 2 \texttt{head = [2,1], x = 2} head = [2,1], x = 2
输出: [1,2] \texttt{[1,2]} [1,2]
这道题要求将原始链表分隔成两部分,第一部分的每个结点的值都小于 x x x,第二部分的每个结点的值都大于或等于 x x x,每个部分的结点相对顺序和原始链表的结点相对顺序相同,然后将第二部分拼接在第一部分的后面。
可以分成两步实现。第一步将原始链表分隔成两个链表,第二步将分隔成的两个链表拼接。
由于需要将原始链表根据结点值和 x x x 的大小关系分隔成两个链表,因此需要创建两个哑结点分别作为分隔成的两个链表的头结点。以哑结点 dummyHead 1 \textit{dummyHead}_1 dummyHead1 为头结点的链表中的每个结点的值都小于 x x x(除了哑节点以外),以哑结点 dummyHead 2 \textit{dummyHead}_2 dummyHead2 为头结点的链表中的每个结点的值都大于或等于 x x x(除了哑节点以外)。遍历原始链表,将每个结点根据结点值拼接到两个链表之一。由于拼接结点的顺序和遍历原始链表中的结点的顺序相同,因此分隔成的两个链表的结点相对顺序一定和原始链表的结点相对顺序相同。
具体做法是,用 temp 1 \textit{temp}_1 temp1 和 temp 2 \textit{temp}_2 temp2 分别表示分隔成的两个链表的最后一个结点,初始时 temp 1 = dummyHead 1 \textit{temp}_1 = \textit{dummyHead}_1 temp1=dummyHead1, temp 2 = dummyHead 2 \textit{temp}_2 = \textit{dummyHead}_2 temp2=dummyHead2,用 temp \textit{temp} temp 表示原始链表中遍历到的结点,初始时 temp = head \textit{temp} = \textit{head} temp=head。根据 temp \textit{temp} temp 的结点值,进行如下操作:
如果 temp . val < x \textit{temp}.\textit{val} < x temp.val<x,则 temp \textit{temp} temp 应拼接在小于 x x x 的链表后面,因此令 temp 1 . next : = temp \textit{temp}_1.\textit{next} := \textit{temp} temp1.next:=temp,然后将 temp 1 \textit{temp}_1 temp1 向后移动一步,将 temp \textit{temp} temp 向后移动一步;
如果 temp . val ≥ x \textit{temp}.\textit{val} \ge x temp.val≥x,则 temp \textit{temp} temp 应拼接在大于或等于 x x x 的链表后面,因此令 temp 2 . next : = temp \textit{temp}_2.\textit{next} := \textit{temp} temp2.next:=temp,然后将 temp 2 \textit{temp}_2 temp2 向后移动一步,将 temp \textit{temp} temp 向后移动一步。
重复上述操作,直到 temp \textit{temp} temp 变成空,此时原始链表中的所有结点都属于分隔成的两个链表之一。将原始链表分隔成两个链表之后,需要将两个链表拼接,拼接操作如下:
大于或等于 x x x 的链表应拼接在小于 x x x 的链表后面,小于 x x x 的链表的最后一个结点是 temp 1 \textit{temp}_1 temp1,大于或等于 x x x 的链表的除了哑节点以外的第一个结点是 dummyHead 2 . next \textit{dummyHead}_2.\textit{next} dummyHead2.next,因此令 temp 1 . next : = dummyHead 2 . next \textit{temp}_1.\textit{next} := \textit{dummyHead}_2.\textit{next} temp1.next:=dummyHead2.next;
大于或等于 x x x 的链表的最后一个结点应为结果链表的最后一个结点,最后一个结点为 temp 2 \textit{temp}_2 temp2,因此令 temp 2 . next : = null \textit{temp}_2.\textit{next} := \text{null} temp2.next:=null。
结果链表的头结点为小于 x x x 的链表的除了哑节点以外的第一个结点,即 dummyHead 1 . next \textit{dummyHead}_1.\textit{next} dummyHead1.next,将其返回即可。
class Solution {
public ListNode partition(ListNode head, int x) {
ListNode dummyHead1 = new ListNode(0);
ListNode dummyHead2 = new ListNode(0);
ListNode temp1 = dummyHead1, temp2 = dummyHead2;
ListNode temp = head;
while (temp != null) {
if (temp.val < x) {
temp1.next = temp;
temp1 = temp1.next;
} else {
temp2.next = temp;
temp2 = temp2.next;
}
temp = temp.next;
}
temp1.next = dummyHead2.next;
temp2.next = null;
return dummyHead1.next;
}
}
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是链表的长度。需要遍历链表一次,对每个结点的操作都是 O ( 1 ) O(1) O(1) 的时间,拼接两个链表的操作也是 O ( 1 ) O(1) O(1) 的时间。
空间复杂度: O ( 1 ) O(1) O(1)。