【題目】 給定一個單向鏈表的頭節點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)。
分析:
一 普通解法:已知數組的partition過程,把鏈表的每一個node放到一個容器(生成一個node類型的數組),在這個數組中進行partition。partition的過程按照值來放,在數組中做到小於pivot的放它左邊,等於pivot的值放中間,大於pivot的值放右邊;在數組中調整好之後,然後從數組中開始重新連接這個鏈表,連完之後返回。但是這個方法需要時間複雜度O(n),
額外空間複雜度O(n)
,而且partition
不能達到穩定性(就是會改變原來的相對順序);
具體步驟如下:
1.先遍歷一遍鏈表,爲了得到鏈表的長度,假設長度爲N。
2.生成長度爲N的Node類型數組,然後遍歷一次鏈表,將節點一次放進數組中
3.在數組中做到小於pivot的放它左邊,等於pivot的值放中間,大於pivot的值放右邊,也就是改進了快排中partition過程。
4.然後從數組中開始重新連接這個鏈表的節點,連完之後返回。
二 進階解法:按照原鏈表各個節點的對應順序將鏈表分解成三部分,小於pivot的、等於pivot的,大於pivot的,之後再將三個連起來即可。這三個鏈表都有自己的兩個指針Head
和Tail
分別代表各自的頭部和尾部,分成三個子鏈表之後,我們只需要遍歷鏈表,然後和給定的值比較,按照條件,向三個鏈表中添加值就可以了,最後把三個鏈表連接起來就可以了。
public class SmallerEqualBigger {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
//普通的需要額外空間O(n)且不能達到穩定性的方法
public static Node listPartition1(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];
i = 0;
cur = head;
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];
}
public static void arrPartition(Node[] nodeArr, int pivot) {
int small = -1;
int big = nodeArr.length;
int index = 0;
while (index != big) {
if (nodeArr[index].value < pivot) {
swap(nodeArr, ++small, index++);
} else if (nodeArr[index].value == pivot) {
index++;
} else {
swap(nodeArr, --big, index);
}
}
}
public static void swap(Node[] nodeArr, int a, int b) {
Node tmp = nodeArr[a];
nodeArr[a] = nodeArr[b];
nodeArr[b] = tmp;
}
//第二種 進階的方法 不需要額外的空間複雜度,且能達到穩定性
public static Node listPartition2(Node head, int pivot) {
Node sH = null; // small head
Node sT = null; // small tail
Node eH = null; // equal head
Node eT = null; // equal tail
Node bH = null; // big head
Node bT = null; // big tail
Node next = null; // save next node
// every node distributed to three lists
while (head != null) {
next = head.next;
head.next = null;
if (head.value < pivot) {
if (sH == null) {
sH = head;
sT = head;
} else {
sT.next = head;
sT = head;
}
} else if (head.value == pivot) {
if (eH == null) {
eH = head;
eT = head;
} else {
eT.next = head;
eT = head;
}
} else {
if (bH == null) {
bH = head;
bT = head;
} else {
bT.next = head;
bT = head;
}
}
head = next;
}
// small and equal reconnect
if (sT != null) {
sT.next = eH;
eT = eT == null ? sT : eT;
}
// all reconnect
if (eT != null) {
eT.next = bH;
}
return sH != null ? sH : eH != null ? eH : bH;
}
public static void printLinkedList(Node node) {
System.out.print("Linked List: ");
while (node != null) {
System.out.print(node.value + " ");
node = node.next;
}
System.out.println();
}
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);
printLinkedList(head1);
// head1 = listPartition1(head1, 4);
head1 = listPartition2(head1, 5);
printLinkedList(head1);
}
}