解题思路
61. 旋转链表
思路一: 循环链表
该题因为要不断地移动链表,可以通过构造循环链表来实现。
- 构造循环链表: 遍历链表,找到链表尾部的最后一个节点,链接链表的头部。同时计算链表的长度n。
- 寻找移动k位后的链表的头部和尾部,并断开头尾
由题意可知,向右移动1位,新的链表头为原来的第n个节点,尾为第n-1个节点,
向右移动2位,新的链表头为n-1个节点,表尾为第n-2个节点…
以此类推,向右移动k位,新的链表尾部为 第n-k%n个节点,新的链表头为第n-k%n+1个节点,就是尾的下一个。
所以由头向后移动 n-k%n-1步,得到尾节点,存储下一个节点为头节点,将尾节点指向null。
思路二: 快慢指针
原链表向右移动k位形成的新链表,就是从原链表最后面开始 第k位节点为头节点的新链表,关键在于找到该头节点的位置!
使用快慢指针,快指针与慢指针保持K个节点的距离,然后一同遍历到链表尾,那样快指针就到了原链表的尾部,快指针往前K-1个节点的位置就是新链表头节点的位置(即慢指针的下一个节点),所以,新链表的尾部就是慢指针,新链表的头部就是慢指针的下一个节点。最后只需断开头尾即可。
代码
方法一:循环链表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
//构造循环链表
public static ListNode rotateRight(ListNode head, int k) {
//空链表、一个节点的链表、移动0次不做处理
if(head == null || head.next == null || k==0) {
return head;
}
int length = 1; //head链表的长度
ListNode head1 = head;
//构成循环链表
while(head1.next!= null) {
head1 = head1.next;
length++;
}
head1.next = head;
//找现链表的头节点和尾结点
int ant = length-k%length; //原链表头节点向右移动(length-k%length)次找到现链表头节点
for(int i=1 ;i<ant; i++) {//移动(length-k%length-1)次找到现链表头节点前一位,即尾结点
head = head.next;
}
//断开尾结点和头节点,同时尾结点要指向null
ListNode last_node = head;
head = head.next;
last_node.next = null;
return head;
}
}
方法一的优化:当移动的次数等于自身长度时,等于不移动
class Solution {
//构造循环链表
public static ListNode rotateRight(ListNode head, int k) {
//空链表、一个节点的链表、移动0次不做处理
if(head == null || head.next == null || k==0) {
return head;
}
int length = 1; //head链表的长度
ListNode head1 = head;
//构成循环链表
while(head1.next!= null) {
head1 = head1.next;
length++;
}
//当移动的次数等于自身长度时,等于不移动
if(k%length == 0) return head;
head1.next = head;
//找现链表的头节点和尾结点
int ant = length-k%length; //原链表头节点向右移动(length-k%length)次找到现链表头节点
for(int i=1 ;i<ant; i++) {//移动(length-k%length-1)次找到现链表头节点前一位,即尾结点
head = head.next;
}
//断开尾结点和头节点,同时尾结点要指向null
ListNode last_node = head;
head = head.next;
last_node.next = null;
return head;
}
}
方法二:快慢指针
// 快慢指针:
public static ListNode rotateRight2(ListNode head, int k) {
//空链表、一个节点的链表、移动0次不做处理
if(head == null || head.next == null || k==0) {
return head;
}
ListNode temp_head = head;
//快指针、慢指针,两指针保持K的距离,那样遍历到最后就可以找到新链表的头节点和尾结点
ListNode fast= head , slow=head;
int length = 1; //链表的长度
while(temp_head.next!=null) {
temp_head = temp_head.next;
length++;
}
//当移动的次数等于自身长度时,等于不移动
if(k%length==0) return head;
//快指针先走k步
for(int i=0 ; i< k%length ; i++) {
fast = fast.next;
}
while(fast.next != null) {
fast = fast.next;
slow = slow.next;
}
ListNode new_head = slow.next;
slow.next = null;
fast.next = head;
return new_head;
}