1. 程式人生 > >演算法題012 -- [Rotate List] by java

演算法題012 -- [Rotate List] by java

題目

將倒數K個節點放在連結串列頭部

舉例
Input 1->2->3->4->5->NULL and k = 2,
Output 4->5->1->2->3->NULL.

分析

不管使用何種方法,基於連結串列的特性,必須要找出三個節點:

  • 輸入連結串列的head節點,這個節點會變成下半部分的head節點
  • 設連結串列長度為 len,那麼需要找出 (len - k) 處的節點,該節點將成為新連結串列的head節點
  • 輸入連結串列的tail節點,該節點需要與 (len -k) 節點連結起來,成為輸出連結串列

程式碼

方法一的思路見文章後面的圖解部分;
方法二的思路簡單,簡述了一下。

package algorithm012;

import algorithm006.ListNode;

public class Algorithm012 {
	
	public static void main(String[] args) {
		ListNode test = getListNode();
		System.out.println(test.toString());
		test = reverseKNodesByLength(test, 2);
		System.out.println
(test.toString()); } /**方法一 * 思路:快慢指標,見文章圖解部分 * 優點:時間複雜度 O(n) 空間複雜度 O(1) * * @param listNode * @param k * @return */ public static ListNode reverseKNodesBy2Pointers(ListNode listNode, int k) { if(k <=0 || null == listNode) return listNode; ListNode preFastNode = null; ListNode fastNode =
listNode; ListNode slowNode = null; int pos = 1; while(fastNode != null) { if(pos > k) { if(null == slowNode) slowNode = listNode; else slowNode = slowNode.next; } preFastNode = fastNode; fastNode = fastNode.next; pos++; } if(pos <= k) return listNode; preFastNode.next = listNode; ListNode headNode = slowNode.next; slowNode.next = null; return headNode; } /**方法二 * 思路:通過計算連結串列的長度,遍歷指定的長度,尋找需要的節點 * 優點:時間複雜度 O(2n) 空間複雜度 O(1) 思路直白簡單 * * @param listNode * @param k * @return */ public static ListNode reverseKNodesByLength(ListNode listNode, int k) { int length = getListNodeLength(listNode); if(length <= k) return listNode; int pos = 1; int dValue = length - k; ListNode originalHeadNode = listNode; ListNode preNode = null; ListNode dValueNode = null; while(listNode != null) { if(pos <= dValue) { dValueNode = listNode; pos++; } preNode = listNode; listNode = listNode.next; } preNode.next = originalHeadNode; ListNode headNode = dValueNode.next; dValueNode.next = null; return headNode; } public static int getListNodeLength(ListNode listNode) { int length = 0; ListNode headNode = listNode; while(headNode != null) { length++; headNode = headNode.next; } return length; } public static ListNode getListNode() { ListNode listNode2 = new ListNode(0); ListNode listNode4 = new ListNode(1); ListNode listNode6 = new ListNode(2); ListNode listNode8 = new ListNode(3); ListNode listNode10 = new ListNode(4); ListNode listNode11 = new ListNode(5); ListNode listNode12 = new ListNode(6); ListNode listNode13 = new ListNode(7); listNode2.next = listNode4; listNode4.next = listNode6; listNode6.next = listNode8; listNode8.next = listNode10; listNode10.next = listNode11; listNode11.next = listNode12; listNode12.next = listNode13; return listNode2; } }

圖解方法一

有題: 將倒數K個節點放在連結串列頭部;於是,把連結串列分成兩個部分:
在這裡插入圖片描述
那麼如果使用兩個節點,該怎麼考慮呢?
結合上面的分析,我們需要知道三個節點的位置,head(len -k)tail
head 和 tail 總是很容易就能知道的,那麼怎麼讓指標指向 (len -k)的位置呢?
現在已知的條件只有 連結串列 和 K,如果反過來想呢?
在這裡插入圖片描述
如果一個指標fastNode前進到了節點K,那麼接下來,再繼續遍歷直到null,走過的路程其實就是len -k,如果在fastNode到了節點K的時候,有一個slowNode開始從head節點走,當fastNode變為null停下來的時候,slowNode也走了len-k:
在這裡插入圖片描述
至此!所需要的三個節點全部有了出處!