第61题:旋转链表

解题思路

61. 旋转链表
思路一: 循环链表
该题因为要不断地移动链表,可以通过构造循环链表来实现。

  1. 构造循环链表: 遍历链表,找到链表尾部的最后一个节点,链接链表的头部。同时计算链表的长度n。
  2. 寻找移动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;
    }
}

image.png

方法一的优化:当移动的次数等于自身长度时,等于不移动
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;
    }
}

image.png

方法二:快慢指针
// 快慢指针:
	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;
	}

image.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值