[算法] - 將單向鏈表按某值劃分成左邊小、 中間相等、 右邊大的形式 ( 額外空間複雜度請達到O(1) )

將單向鏈表按某值劃分成左邊小、 中間相等、 右邊大的形式


【 題目】 給定一個單鏈表的頭節點head, 節點的值類型是整型, 再給定一個整
數pivot。 實現一個調整鏈表的函數, 將鏈表調整爲左部分都是值小於pivot的
節點, 中間部分都是值等於pivot的節點, 右部分都是值大於pivot的節點。
【 進階】 在實現原問題功能的基礎上增加如下的要求
【 要求】 調整後所有小於pivot的節點之間的相對順序和調整前一樣
【 要求】 調整後所有等於pivot的節點之間的相對順序和調整前一樣
【 要求】 調整後所有大於pivot的節點之間的相對順序和調整前一樣
【 要求】 時間複雜度請達到O(N), 額外空間複雜度請達到O(1)。

筆試用:變成數組,數組上partition,然後再返回鏈表

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數組Partition
		arrPartition(nodeArr, pivot);
        //變成鏈表
		for (i = 1; i != nodeArr.length; i++) {
			nodeArr[i - 1].next = nodeArr[i];
		}
		nodeArr[i - 1].next = null;
		return nodeArr[0];//返回鏈表的head
	}

	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) {//如果小於p,
				swap(nodeArr, ++small, index++);//首先交換small和index的位置,然後各自+1,表示
			} 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;
	}

面試:

6個指針 Head tail equal,依次遍歷原鏈表,注意邊界連接問題

鏈表if的時候很多是爲了next不出錯,

if (sT != null) {//如果有小於區域
            sT.next = eH;不用管eH是什麼,就算是null這句話也是對的。

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;//因爲涉及到鏈表的重連,原先的next結構要在新的裏面初始化成null,所以需要先null
            
			if (head.value < pivot) {
				if (sH == null) {
					sH = head;
					sT = head;
				} else {
					sT.next = head;//老的 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
       //邊界問題出錯,就是next調用的時候出錯,所以這裏就是先做了if
		if (sT != null) {//如果有小於區域
			sT.next = eH;//如果有等於區域eT=eT,如果沒有等於區域但是有小於區域eT=sT
			eT = eT == null ? sT : eT;//下一步,誰去連eh,誰就變成eT
		}//上面的eT很巧妙~ ~ ~如果沒有小於區域也沒有等於區域,也就是上下if都沒有跑,此時的eT就是eT,沒變。
   
		// all reconnect 
		if (eT != null) {//就是如果有小於或等於的區域
			eT.next = bH;
		}
    
    //如果sh存在就是sh,如果不存在但是存在eh就選eh,否則就選bh返回
		return sH != null ? sH : eH != null ? eH : bH;
	}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章