题目描述:
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
示例 2:
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL
思想:
这道题主要先理解题意,就是倒着数k个node,从那开始到结尾和之前那部分对调,举个例子就是,4->5拿前面来,1->2->3拿后面去。熟悉的faster/slower双指针解决就好(看到这种linkedlist,倒着数数的,就条件反射了)
- 先对faster设步长为n,然后faster和slower再一起走,知道faster.next==null,说明slower指向要倒着数的开始点的前一个位置。
- 所以slow.next就是要返回的链表的第一个结点,保存一下。
- 然后把fast.next接到head上,slow.next存为null,作队尾。这样就把list给rotate了。
PS:需要先计算一下链表长度,然后取个余数,意味k太大的话,就一圈又一圈的循环了。
class ListNode{
int val;
ListNode next;
public ListNode(int x) {
val = x;
}
}
public class test1 {
public static ListNode rotateRight(ListNode head, int k) {
//处理特殊情况
if(head == null || head.next == null || k == 1) return head;
//新建虚拟头结点
ListNode dummy = new ListNode(-1);
dummy.next = head;
//初始化快慢指针和计数指针
ListNode slow = head, fast = head, countlen = head;
//首先取得链表的长度
int len = 0;
while(countlen != null) {
len++;
countlen = countlen.next;
}
//更新k
k = k % len;
//慢指针先走k步
for(int i = 0; i < k; i++) {
fast = fast.next;
}
//快慢指针同时走
while(fast.next != null) {
fast = fast.next;
slow = slow.next;
}
//此时,slow指向倒数第1个结点,fast指向倒数第k+1指针
//翻转链表,详情画图
dummy.next = slow.next;
fast.next = head;
slow.next = null;
return dummy.next;
}
//初始化链表
public static void add(ListNode node, int[] data) {
ListNode temp = node;
if(data.length == 0) return;
for(int i = 0; i < data.length; i++) {
temp.next = new ListNode(data[i]);
temp = temp.next;
}
}
//打印链表
public static void LinkedPrint(ListNode node) {
if(node == null) return;
while(node != null) {
System.out.println(node.val + " ");
node = node.next;
}
}
public static void main(String[] args) {
ListNode p = new ListNode(0);
int [] nums = {1, 2, 3, 4, 5};
add(p, nums);
ListNode result = rotateRight(p.next, 2);
LinkedPrint(result);
}
}