题目描述
给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。
你应当保留两个分区中每个节点的初始相对位置。
示例:
输入: head = 1->4->3->2->5->2, x = 3
输出: 1->2->2->4->3->5
题目分析
这道题有点难懂,以我自己的理解来看,就是找到比x小的,那么我放前面去,比他大的就留原地。不需要按照大小给链表排序。这样就可以创建两个链表,一个保存遍历到比x小的值,另一个就保留原地保存到另一个链表,最后将这两个链表连接起来就行。
源码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode partition(ListNode head, int x) {
ListNode head1 = new ListNode(0);
ListNode head2 = new ListNode(0);
ListNode node1 = head1;
ListNode node2 = head2;
//两个链表
while (head != null){
if (head.val<x){
//小于就保存在node1里
node1.next = head;
head = head.next;
node1 = node1.next;
node1.next = null;
}else {
//大于等于的到node2里,不需要排序
node2.next = head;
head = head.next;
node2 = node2.next;
node2.next = null;
}
}
node1.next = head2.next;
//最后连起来
return head1.next;
}
}
改进
还有一种方法那就是在原地交换顺序,先找到小于x的最后一个节点,然后当碰到大于等于x的节点时,交换一下顺序。当遍历完时就已经换好了,有点像是双指针的感觉。
改进代码
class Solution {
public ListNode partition(ListNode head, int x) {
ListNode firstNode=new ListNode(Integer.MIN_VALUE);//head前加一个节点
firstNode.next=head;
ListNode pNode=firstNode;
while(pNode.val<x && pNode.next!=null && pNode.next.val<x){//找到连续小于x的最后一个pNode
pNode=pNode.next;
}
ListNode y=pNode;
while(y.next!=null){//找到需要插到前面的节点y.next
if(y.next.val<x){//插到pNode后面,更新pNode,并且将y.next前后连接起来.
ListNode temp1=pNode.next;
ListNode temp2=y.next.next;
pNode.next=y.next;
y.next.next=temp1;
pNode=y.next;
y.next=temp2;
}
else{
y=y.next;
}
}
return firstNode.next;
}
}
分析
第一个时间复杂度为O(n)
第二个就是O(n),空间的复杂度第一个要高一点,因为创建了新的地址。
难点
遇到链表题,令人头疼的就是要考虑到两个数据之间的连接。如果没有空间的限制的话,用分治法的思想就很好。
小结
在不限制空间的情况下,不管是交换顺序还是排序,分治思想是一个很好的办法,具体可以模仿快速排序的做法。
[1]https://leetcode-cn.com/problems/partition-list/submissions/