演算法題012 -- [Rotate List] by java
阿新 • • 發佈:2018-11-22
題目
將倒數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
:
至此!所需要的三個節點全部有了出處!