旋转链表

博客主要讲述给定一个链表,需将链表每个节点向右移动 k 个位置,k 为非负数,还给出了示例。

摘要生成于 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
public class RotateRight {
	public class ListNode {
		int val;
		ListNode next;

		ListNode(int x) {
			val = x;
		}
	}

	public ListNode rotateRight(ListNode head, int k) {
		if (head == null || k < 0){
			return head;
		}
		ListNode tail = head;
		ListNode pre = head;
		int len = 1;
		int pos = 0;
		while (tail.next != null) {
			tail = tail.next;
			len++;
		}
		if ((pos = k % len) == 0){
			return head;
		}
		for (int i = 0; i < len - pos - 1; i++) {
			pre = pre.next;
		}
		ListNode res = pre.next;
		pre.next = null;
		tail.next = head;
		return res;
	}
}
### 解题思路 解决 LeetCode 61 题“旋转链表”的核心思想是找到旋转后的新头节点并重新连接链表。为了高效处理,通常采用以下步骤: - **计算链表长度**:遍历整个链表以确定其长度 `length`。 - **特殊情况判断**:如果 `k == 0` 或者链表为空,则直接返回原头节点。 - **取模运算优化旋转次数**:由于链表旋转 `length` 次后会恢复原状,因此只需要执行 `k % length` 次旋转。 - **快慢指针或前后指针法**:使用双指针方法快速定位新头节点和尾节点。 - **链表拼接**:将链表尾部连接到头部,并在合适的位置断开形成新的链表结构。 --- ### 方法一:快慢指针 + 取模优化 该方法通过快慢指针来寻找新头节点与旧尾部的连接点。 ```java class Solution { public ListNode rotateRight(ListNode head, int k) { if (head == null || k <= 0) return head; ListNode front = head, behind = head; int len = 0; // 找出链表长度,并调整front指针位置 while (k-- > 0) { front = front.next; len++; if (front == null) { k %= len; front = head; } } // 如果不需要旋转,直接返回原头节点 if (front == head) return head; // 同时移动front和behind,直到front指向最后一个节点 while (front.next != null) { front = front.next; behind = behind.next; } // 调整链表连接关系 ListNode newHead = behind.next; front.next = head; behind.next = null; return newHead; } } ``` --- ### 方法二:整体长度计算 + 切分点查找 此方法首先计算链表总长度,再根据 `k % length` 确定切分点,然后进行节点重连。 ```java class Solution { public ListNode rotateRight(ListNode head, int k) { if (head == null || k == 0) return head; ListNode node = head; int length = 0; // 计算链表长度 while (node.next != null) { node = node.next; length++; } length++; // 取模优化旋转次数 k = k % length; if (k == 0) return head; // 将链表首尾相连 node.next = head; // 移动指针到断开位置 for (int i = 0; i < length - k; i++) { node = node.next; } // 新头节点为当前节点的下一个节点 ListNode newHead = node.next; node.next = null; return newHead; } } ``` --- ### 方法三:快慢指针 + 明确切分点 该方法明确计算出切分点位置,并通过快慢指针分别定位到关键节点。 ```java class Solution { public ListNode rotateRight(ListNode head, int k) { if (head == null) return head; int length = 1; ListNode oldTail = head; // 获取链表长度 while (oldTail.next != null) { oldTail = oldTail.next; length++; } // 取模优化 k = k % length; if (k == 0) return head; // 找到新的尾节点 ListNode newTail = head; for (int i = 0; i < length - k - 1; i++) { newTail = newTail.next; } // 新头节点和尾节点的连接 ListNode newHead = newTail.next; newTail.next = null; oldTail.next = head; return newHead; } } ``` --- ### 时间复杂度分析 - **时间复杂度**:`O(n)`,其中 `n` 是链表长度。需要两次遍历链表(一次计算长度,一次调整指针)。 - **空间复杂度**:`O(1)`,仅使用常数级额外空间。 --- ### 总结 以上三种解法均基于快慢指针或前后指针的思想,结合取模操作优化旋转次数,从而避免不必要的重复操作。不同实现方式各有侧重,但核心逻辑相似,适用于不同场景下的链表旋转问题。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值