题目描述
给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。
你应当保留两个分区中每个节点的初始相对位置。(原地)
示例:
输入: head = 1->4->3->2->5->2, x = 3
输出: 1->2->2->4->3->5
分析
如果没有原地的要求,可以使用三路partition方法解决。设置一个前驱结点和一个现结点,开头可能已经有部分结点是符合要求的,跳过它们。接着依次遍历下一个结点,若大于等于预定值,则现结点向下移动一位,若小于则将其与原链表断开,并连接到前驱结点的下一个位置,以此类推。
public ListNode partition(ListNode head, int x) {
if (head == null)
return null;
ListNode start = new ListNode(-1);
start.next = head;
ListNode pre = start;
ListNode cur = start.next;
// 跳过已经分隔好的
while (cur != null && cur.val < x) {
pre = cur;
cur = cur.next;
}
while (cur != null) {
while (cur.next != null && cur.next.val >= x) cur = cur.next;
if (cur.next == null) return start.next;
ListNode tmp = cur.next;
cur.next = cur.next.next; // 断开
tmp.next = pre.next;
pre.next = tmp; // 连接
pre = pre.next;
}
return start.next;
}
另一个思路,设置两个头指针分别操作原链表。循环开始时,两个指针将跳过不属于自己的结点,连接起属于自己的结点,当循环结束时,这两个指针保存了大于等于 x 和小于 x 的两部分。最后注意要将大于等于 x 的子链表的最后部分手动置位空,然后将其头结点连接到小于 x 子链表的后面即可。
public ListNode partition(ListNode head, int x) {
ListNode m = new ListNode(0), n = new ListNode(0);
ListNode p = m, q = n;
while (head != null) {
if (head.val < x)
p = p.next = head;
else
q = q.next = head;
head = head.next;
}
q.next = null;
p.next = n.next;
return m.next;
}