问题:给定一个单向链表的头节点head,节点的值类型是整型,再给定一个整数point。实现一个调整链表的函数,将链表调整为左部分都是值小于pointt的节点,中间部分都是值等于pivot的节点,右部分都是值大于point的节点。除这个要求外,对调整后的节点顺序没有更多的要求。
第一种解法:类似于荷兰国旗,借助一个数组,把链表所有节点放入一个数组中,将此数组进行三个区域的划分。
//划分结束后再将数组依次next串起来,(在分到数组中时可以不用切断next,因为后面的赋值会覆盖掉,)返回数组中第一个元素即可(数组类型为Node)
//额外空间复杂度O(n)链表长度为n 达不到稳定性
链表结构:
public static class Node {
public int value;
public Node next;
public Node(int a) {
this.value = a;
}
}
借助数组方式实现:
public static Node listPartition1(Node head, int point) {
if (head == null || head.next == null)
return head;
int i = 0;
Node cur = head;
while (cur != null) {
cur = cur.next;
i++;
}
Node nodelist[] = new Node[i];
cur = head;
for (i = 0; i < nodelist.length; i++) {
nodelist[i] = cur;
cur = cur.next;
//指向空
nodelist[i].next=null;
}
arrpartition(nodelist, point);
// 数组已经划分为三部分
for (i = 0; i < nodelist.length - 1; i++) {
nodelist[i].next = nodelist[i + 1];
}
nodelist[i].next = null;
return nodelist[0];
}
private static void arrpartition(Node[] nodelist, int point) {
int small = -1;
int i = 0;
int big = nodelist.length;
while (i < big) {
if (nodelist[i].value < point) {
swap(nodelist, ++small, i++);
} else if (nodelist[i].value > point) {
swap(nodelist, --big, i);
} else
i++;
}
}
private static void swap(Node[] nodelist, int i, int j) {
Node t = nodelist[i];
nodelist[i] = nodelist[j];
nodelist[j] = t;
}
第二种解法: 额外空间复杂度O(1)只用几个节点进行划分,可以完成稳定性。借助六个节点,分别为小于等于大于区域的头部和尾部,遍历链表,依次将相应的节点挂在相应区域的位置。
(注意节点next指针的处理,当把head挂上去时,为保证不出混乱,先记录下来head.next的节点,然后把head.next设置为空,最后再将节点连回去时,要注意可能某区域为空)
代码:
public static Node listPartition2(Node head, int point) {
if (head == null || head.next == null)
return head;
Node Sst = null;
Node Sed = null;
Node Est = null;
Node Eed = null;
Node Lst = null;
Node Led = null;
Node next=null;
while (head != null) {
next=head.next;
head.next=null;//保证挂在分组上的节点仅仅是这一个节点,而不是一大串节点,不然会乱掉
if (head.value > point) {
if (Lst == null) {
Lst = head;
Led = head;
} else {
Led.next = head;
Led = head;
}
} else if (head.value < point) {
if (Sst == null) {
Sst = head;
Sed = head;
} else {
Sed.next = head;
Sed = head;
}
} else {
if (Est == null) {
Est = head;
Eed = head;
} else {
Eed.next = head;
Eed = head;
}
}
head = next;
}
//空区处理,如果中间区域存在,与大区域相连(大区域存不存在并不重要,如果不存在即为null)
//如果不存在,中间区域头就和大区域头合并。
if (Est != null)
Eed.next = Lst;
else if (Est == null) {
Est = Lst;
}
//如果小于区域不为空,与等于区域相连,返回值为小于区域头节点。如果为空,则返回值为等于区域头节点
if (Sst != null)
Sed.next = Est;
if (Sst == null) {
return Est;
}
return Sst;
/* if (Sed != null) {
Sed.next = Est;
Eed = Eed == null ? Sed : Eed;
}
all reconnect
if (Eed != null) {
Eed.next = Lst;
}
return Sst != null ? Sst : Est != null ? Est : Lst;
*/
}
包括数组的荷兰国旗实现,也可以借助链表达到稳定性
(以下可忽略)
public class smallequalbig {
public static class Node {
public int value;
public Node next;
public Node(int a) {
this.value = a;
}
}
public static Node listPartition1(Node head, int point) {
if (head == null || head.next == null)
return head;
int i = 0;
Node cur = head;
while (cur != null) {
cur = cur.next;
i++;
}
Node nodelist[] = new Node[i];
cur = head;
for (i = 0; i < nodelist.length; i++) {
nodelist[i] = cur;
cur = cur.next;
//指向空
nodelist[i].next=null;
}
arrpartition(nodelist, point);
// 数组已经划分为三部分
for (i = 0; i < nodelist.length - 1; i++) {
nodelist[i].next = nodelist[i + 1];
}
nodelist[i].next = null;
return nodelist[0];
}
private static void arrpartition(Node[] nodelist, int point) {
int small = -1;
int i = 0;
int big = nodelist.length;
while (i < big) {
if (nodelist[i].value < point) {
swap(nodelist, ++small, i++);
} else if (nodelist[i].value > point) {
swap(nodelist, --big, i);
} else
i++;
}
}
private static void swap(Node[] nodelist, int i, int j) {
Node t = nodelist[i];
nodelist[i] = nodelist[j];
nodelist[j] = t;
}
// 额外空间复杂度O(1)只用几个节点进行划分,可以完成稳定性。注意节点next指针的处理。最后分组为空时的处理
public static Node listPartition2(Node head, int point) {
if (head == null || head.next == null)
return head;
Node Sst = null;
Node Sed = null;
Node Est = null;
Node Eed = null;
Node Lst = null;
Node Led = null;
Node next=null;
while (head != null) {
next=head.next;
head.next=null;//保证挂在分组上的节点仅仅是这一个节点,而不是一大串节点,不然会乱掉
if (head.value > point) {
if (Lst == null) {
Lst = head;
Led = head;
} else {
Led.next = head;
Led = head;
}
} else if (head.value < point) {
if (Sst == null) {
Sst = head;
Sed = head;
} else {
Sed.next = head;
Sed = head;
}
} else {
if (Est == null) {
Est = head;
Eed = head;
} else {
Eed.next = head;
Eed = head;
}
}
head = next;
}
//空区处理,如果中间区域存在,与大区域相连(大区域存不存在并不重要,如果不存在即为null)
//如果不存在,中间区域头就和大区域头合并。
if (Est != null)
Eed.next = Lst;
else if (Est == null) {
Est = Lst;
}
//如果小于区域不为空,与等于区域相连,返回值为小于区域头节点。如果为空,则返回值为等于区域头节点
if (Sst != null)
Sed.next = Est;
if (Sst == null) {
return Est;
}
return Sst;
/* if (Sed != null) {
Sed.next = Est;
Eed = Eed == null ? Sed : Eed;
}
all reconnect
if (Eed != null) {
Eed.next = Lst;
}
return Sst != null ? Sst : Est != null ? Est : Lst;
*/
}
public static void main(String[] args) {
Node head1 = new Node(7);
head1.next = new Node(9);
head1.next.next = new Node(1);
head1.next.next.next = new Node(8);
head1.next.next.next.next = new Node(5);
head1.next.next.next.next.next = new Node(2);
head1.next.next.next.next.next.next = new Node(5);
//Node head1 = null;
printLinkedList(head1);
head1 = listPartition2(head1, 2);// 更改新的头节点
printLinkedList(head1);
}
private static void printLinkedList(Node head) {
System.out.println("Node List:");
while (head != null) {
System.out.print(head.value + " ");
head = head.next;
}
System.out.println();
}
}