【题目】 给定一个单向链表的头节点head,节点的值类型是整型,再给定一个 整 数pivot。实现一个调整链表的函数,将链表调整为左部分都是值小于 pivot 的节点,中间部分都是值等于pivot的节点,右部分都是值大于 pivot的节点。 除这个要求外,对调整后的节点顺序没有更多的要求。 例如:链表9->0->4->5>1,pivot=3。 调整后链表可以是1->0->4->9->5,也可以是0->1->9->5->4。总 之,满 足左部分都是小于3的节点,中间部分都是等于3的节点(本例中这个部 分为空),右部分都是大于3的节点即可。对某部分内部的节点顺序不做 要求。
进阶: 在原问题的要求之上再增加如下两个要求。 在左、中、右三个部分的内部也做顺序要求,要求每部分里的节点从左 到右的 顺序与原链表中节点的先后次序一致。 例如:链表9->0->4->5->1,pivot=3。 调整后的链表是0->1->9->4->5。 在满足原问题要求的同时,左部分节点从左到 右为0、1。在原链表中也 是先出现0,后出现1;中间部分在本例中为空,不再 讨论;右部分节点 从左到右为9、4、5。在原链表中也是先出现9,然后出现4, 最后出现5。 如果链表长度为N,时间复杂度请达到O(N),额外空间复杂度请达到O(1)。
解决思路:
- 首先我们先满足进阶之前的要求,只需要将链表调整成,左边小于参考值,中间等于参考值,右边大于参考值。我们可以通过一盒辅助数组,将链表元素全部拷贝过去,然后对数组执行调整,调整思路可以参考快速排序的思想,将数组分为三个区域。
核心代码:
//通过数组进行换划分
public static void arrPartition(Node[] nodeArr,int pivot){
int small=-1;
int big=nodeArr.length;
int index=0;
while (index!=big){
if (nodeArr[index].data<pivot){
aswap(nodeArr,++small,index++);
}else if (nodeArr[index].data==pivot){
index++;
}else {
aswap(nodeArr,--big,index);
}
}
}
- 满足进阶条件,即,保持原来相对位置不变,并且空间复杂度为O(N),这就使得我们不能够借用辅助空间来完成。我们可以将原链表拆分成小于,等于,大于区域的小链表,然后去遍历原列表,将大于,小于,等于数分别放到对应链表中。最后将三个链表连接起来就可以了。
eg:第一次找到第一个小于参考值的数。将它放进小于区域,这样就保证了在前面小于参考值的数先进入小于区域,然后整体就保证了相对位置不变。
核心代码:
//方法二:不需要辅助数组,链表拆分成小于部分,等于部分,大于部分。
// 三个小链表,最后在合成,空间复杂度为O(N)
public static Node partition2(Node head,int pivot){
Node sH=null;//small head
Node sE=null;//small end
Node eH=null;//equal head
Node eE=null;//equal end
Node bH=null;//big head
Node bE=null;//big end
Node next=null;
while (head!=null){
next=head.next;
head.next=null;
if (head.data<pivot){
if (sH == null) {
sH=head;
sE=head;
}else {
sE.next=head;
sE=head;
}
}else if(head.data==pivot){
if (eH==null){
eH=head;
eE=head;
}else {
eE.next=head;
eE=head;
}
}else {
if (bH==null){
bH=head;
bE=head;
}else {
bE.next=head;
bE=head;
}
}
head=next;
}
//将小于和等于链表进行连接
if (sE!=null){
sE.next=eH;
eE=eE==null?sE:eE;
}
//连接整个链表
if (eE!=null){
eE.next=bH;
}
return sH!=null?sH:eH!=null?eH:bH;
}
完整代码:
package basic_class_03;
/**
* 类名:Code_12_SmallerEqualBigger<br>
* 功能:将单链表按某值进行划分成左边小,中间想等,右边大的形式<br>
* 作者:java战士<br>
* 日期:2019/9/4<br>
* 版本:v1.0.0
* 历史修订:
*/
public class Code_12_SmallerEqualBigger {
public static class Node{
public int data;
public Node next;
public Node(int data) {
this.data = data;
}
}
//第一种方法将链表拷贝到数组中然后进行划分,最后在数组考回链表中,
// 这种做法空间复杂度为O(),没有要求保持原来的相对顺序不变
public static Node partition1(Node head,int pivot){
if (head==null){
return head;
}
Node cur=head;
int i=0;
while (cur!=null){
i++;
cur=cur.next;
}
Node[] nodeArr=new Node[i];
cur=head;
i=0;
for (i=0;i!=nodeArr.length;i++){
nodeArr[i]=cur;
cur=cur.next;
}
arrPartition(nodeArr,pivot);
for (i=1;i<nodeArr.length;i++){
nodeArr[i-1].next=nodeArr[i];
}
nodeArr[i-1].next=null;
return nodeArr[0];
}
//方法二:不需要辅助数组,链表拆分成小于部分,等于部分,大于部分。
// 三个小链表,最后在合成,空间复杂度为O(N)
public static Node partition2(Node head,int pivot){
Node sH=null;//small head
Node sE=null;//small end
Node eH=null;//equal head
Node eE=null;//equal end
Node bH=null;//big head
Node bE=null;//big end
Node next=null;
while (head!=null){
next=head.next;
head.next=null;
if (head.data<pivot){
if (sH == null) {
sH=head;
sE=head;
}else {
sE.next=head;
sE=head;
}
}else if(head.data==pivot){
if (eH==null){
eH=head;
eE=head;
}else {
eE.next=head;
eE=head;
}
}else {
if (bH==null){
bH=head;
bE=head;
}else {
bE.next=head;
bE=head;
}
}
head=next;
}
//将小于和等于链表进行连接
if (sE!=null){
sE.next=eH;
eE=eE==null?sE:eE;
}
//连接整个链表
if (eE!=null){
eE.next=bH;
}
return sH!=null?sH:eH!=null?eH:bH;
}
//通过数组进行换划分
public static void arrPartition(Node[] nodeArr,int pivot){
int small=-1;
int big=nodeArr.length;
int index=0;
while (index!=big){
if (nodeArr[index].data<pivot){
aswap(nodeArr,++small,index++);
}else if (nodeArr[index].data==pivot){
index++;
}else {
aswap(nodeArr,--big,index);
}
}
}
public static void aswap(Node[] nodeArr,int a,int b){
Node temp=nodeArr[a];
nodeArr[a]=nodeArr[b];
nodeArr[b]=temp;
}
public static void printLinkList(Node head){
System.out.print("Linked List:");
while (head!=null){
System.out.print(head.data+" ");
head=head.next;
}
System.out.println();
}
public static void main(String[] args){
Node head1=new Node(9);
head1.next=new Node(0);
head1.next.next=new Node(4);
head1.next.next.next=new Node(5);
head1.next.next.next.next=new Node(1);
printLinkList(head1);
//head1=partition1(head1,4);
head1=partition2(head1,3);
printLinkList(head1);
}
}
结果展示:(以3作为参考值)