[算法基础] 链表操作-旋转链表

本文介绍了一种链表操作——旋转,即将链表每个节点向右移动k个位置的方法。提供了两种解题思路:一是通过不断将链表的最后一项拿到头部,重复k%length次;二是优化方法,通过首尾相连,按既定次数循环,最终断开得到新链表。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

给定一个链表,旋转链表,将链表每个节点向右移动 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大于链表长度length,则只需要重复上述步骤k % length次。

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} k
 * @return {ListNode}
 */
var rotateRight = function(head, k) {
  	// 如果是 空链表或者只有一个元素的链表,则返回该链表
	if(!head || !head.next) return head
	// 设置指针,指向头部
	var cur = head
	// 从头部开始循环,获取链表长度。由于头部也是一个节点,所以 length 初始值为1
	var length = 1;
	while(cur.next) {
	    cur = cur.next
	    length++
	}
	// 获取实际要重复的次数
	var num = k % length
	// 用一个新指针指向头部
	var node = head
	
	// 拿掉最后一个, 把它放在头部, 重复num次
	while(num > 0){
	  
	  var last = node
	  // 拿到倒数第二个
	  while (last.next && last.next.next) {
	    last = last.next
	  }
	  // 获取最后一项的值
	  var val = last.next.val
	  
	  // 去掉最后一项
	  last.next = null
	  
	  // 把最后一项的值 往头部添加
	  let vhead = new ListNode(val)
	  vhead.next = node
	  node = vhead
	  num--
	}
	return node
};

方法二

对于方法一来说,由于是双层循环,时间复杂度比较高。我们可以做一些优化。
对于链表来说,最终的长度是不变的,其实我们无需每次循环都找到倒数第二个节点作为尾部节点,只需要将链表首尾相连,按照既定的循环次数进行循环,最终断开即可。
实现方法也很直接。

  1. 将链表首尾相连,计算出链表的长度length和步数k % length
  2. 找到新的链表头,由于是从链表尾部走k % length步,就相当于从链表头走lengt - k % length,链表尾部是链表头部前一个,即length - k % length - 1个节点。
  3. 断开环,并返回新的链表头。

此处,我们同样可以使用双指针共同前进完成。

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} k
 * @return {ListNode}
 */
var rotateRight = function(head, k) {
  	// 如果是 空链表或者只有一个元素的链表,则返回该链表
	if(!head || !head.next) return head
	var cur = head
	// 从头部开始循环,获取链表长度。由于头部也是一个节点,所以 length 初始值为1
	var length = 1;
	while(cur.next) {
	    cur = cur.next
	    length++
	}
	// 获取实际要重复的次数
	var num = k % length
	// 链表闭环
	cur.next = head
	var new_list = head
	// 找到新的尾部 new_tail : 走length -  k % length - 1 步
	// 找到新的头部 new_head : 走length -  k % length 步
	for(var i = 0;i < length - num - 1 ; i++){
		new_tail = new_tail.next
	}
	var new_head = new_tail.next
	new_tail.next = null
	return new_head
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值