算法题012 -- [Rotate List] by java

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cjh_android/article/details/84098912

题目

将倒数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:
在这里插入图片描述
至此!所需要的三个节点全部有了出处!

猜你喜欢

转载自blog.csdn.net/cjh_android/article/details/84098912