LeetCode 61——旋转链表
1. 题目

2. 解答
2.1. 方法一
将链表每个节点向右移动 1 个位置,其实就是让链表最后一个结点指向第一个结点。
因此,向右移动 k 个位置就重复上述过程 k 次即可。
然后,我们注意到,若链表有 n 个结点,则移动 n 次后就还是原链表。
原始链表 1->2->3->NULL
向右旋转 1 步: 3->1->2->NULL
向右旋转 2 步: 2->3->1->NULL
向右旋转 3 步: 1->2->3->NULL
实际上,若链表有 n 个结点,我们只需要移动 n % k 次即可。
确定链表有多少个结点,我们则可以用快慢指针法。

- 偶数个结点时,结点个数等于 i * 2。

- 奇数个结点时,结点个数等于 i * 2 + 1。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if (head == NULL || head->next == NULL) return head;
int node_num = 0; // 链表的结点个数
ListNode* slow = head;
ListNode* fast = head;
// 利用快慢指针确定链表的结点总个数
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
node_num++;
}
if (fast) // 奇数个结点
{
node_num = node_num * 2 + 1;
}
else // 偶数个结点
{
node_num = node_num * 2;
}
// 若链表有 K 个结点,向右移动 K 个位置就还是原链表
// 因此我们只需要移动 K % node_num 次即可
if (k % node_num == 0) return head;
else k = k % node_num;
ListNode *temp = head;
ListNode *last_node = NULL;
for (int i = 0; i < k; i++)
{
// 向右移动 1 个位置就是让最后一个结点指向第一个结点
// 先找到倒数第二个结点
while (temp->next->next)
{
temp = temp->next;
}
// 最后一个结点指向第一个结点,倒数第二个节点指向 NULL
last_node = temp->next;
temp->next = NULL;
last_node->next = head;
head = last_node;
temp = head;
}
return head;
}
};
2.2. 方法二
上面的算法中每次将链表结点向右移动 1 个位置的时候,我们都要遍历一次链表,效率较低。
针对链表 1->2->3->4->5->NULL,如果要将链表每个结点向右移动 2 个位置,那倒数第 2 个结点就是旋转后新链表的起始位置;如果要将链表每个结点向右移动 3 个位置,那倒数第 3 个结点就是旋转后新链表的起始位置;而如果要将链表每个结点向右移动 33 个位置,那倒数第 3 个结点就是旋转后新链表的起始位置。
更一般的情况下,若链表长度为 n,移动次数为 k,旋转后链表的起始位置就是原链表倒数第 k % n 个结点。
在上面的例子中,假设新链表的起始位置是结点 4,那链表就被分成了两部分。1->2->3 和 4->5->NULL,我们要做的就是把 1->2->3 拼接在 4->5->NULL 后即可。
实现思路是这样的:
我们先通过快慢指针确定链表长度 n,然后找到旋转后链表起始位置的上一个结点,记为 new_head_last,然后从起始位置 new_head 开始向后遍历,当到达 NULL 时,将 head 指向的头结点拼接在 new_head 后面,然后再将新链表的最后一个结点也即 new_head_last 后面置为 NULL 即可。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if (head == NULL || head->next == NULL) return head;
int node_num = 0; // 链表的结点个数
int mid_num = 0;
ListNode* slow = head;
ListNode* fast = head;
// 利用快慢指针确定链表的结点总个数
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
mid_num++;
}
if (fast) // 奇数个结点
{
node_num = mid_num * 2 + 1;
}
else // 偶数个结点
{
node_num = mid_num * 2;
}
// 若链表有 K 个结点,向右移动 K 个位置就还是原链表
// 因此我们只需要移动 K % node_num 次即可
if (k % node_num == 0) return head;
else k = k % node_num;
int which_node_is_new = 0; // 旋转后的头结点是第几个节点
ListNode* new_head = NULL;
ListNode* new_head_last = NULL;
// 查找旋转后头结点的上一个结点
// 此时 slow 指针指向中间结点,分为在 slow 前还是在 slow 后
which_node_is_new = node_num - k;
if (which_node_is_new > node_num / 2)
{
new_head_last = slow;
for (int i = 0; i < which_node_is_new - mid_num - 1; i++)
{
new_head_last = new_head_last->next;
}
}
else
{
new_head_last = head;
for (int i = 1; i < which_node_is_new; i++)
{
new_head_last = new_head_last->next;
}
}
new_head = new_head_last->next;
ListNode* temp = new_head;
while (temp->next)
{
temp = temp->next;
}
temp->next = head;
new_head_last->next = NULL;
return new_head;
}
};
获取更多精彩,请关注「seniusen」!

LeetCode 61——旋转链表的更多相关文章
- Java实现 LeetCode 61 旋转链表
61. 旋转链表 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: 1->2->3->4->5->NULL, k = ...
- leetcode 61. 旋转链表
题目描述: 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: 1->2->3->4->5->NULL, k = 2 输 ...
- LeetCode 61——旋转链表(JAVA)
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: 1->2->3->4->5->NULL, k = 2 输出: 4-& ...
- LeetCode 61. 旋转链表(Rotate List)
题目描述 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: 1->2->3->4->5->NULL, k = 2 输出 ...
- LeetCode:旋转链表【61】
LeetCode:旋转链表[61] 题目描述 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: 1->2->3->4->5- ...
- leetcode网解题心得——61. 旋转链表
目录 leetcode网解题心得--61. 旋转链表 1.题目描述 2.算法分析: 3.用自然语言描述该算法 4.java语言实现 5.C语言实现 leetcode网解题心得--61. 旋转链表 1. ...
- 【LeetCode】61. 旋转链表
61. 旋转链表 知识点:链表: 题目描述 给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置. 示例 输入:head = [1,2,3,4,5], k = 2 输出:[4 ...
- 61. 旋转链表-leetcode
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: 1->2->3->4->5->NULL, k = 2 输出: 4-& ...
- leetcode刷题-61旋转链表
题目 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: 1->2->3->4->5->NULL, k = 2输出: 4 ...
随机推荐
- 【题解】POJ 2115 C Looooops (Exgcd)
POJ 2115:http://poj.org/problem?id=2115 思路 设循环T次 则要满足A≡(B+CT)(mod 2k) 可得 A=B+CT+m*2k 移项得C*T+2k*m=B-A ...
- ASP.NET mvc 验证码 (转)
ASP.net 验证码(C#) MVC http://blog.163.com/xu_shuhao/blog/static/5257748720101022697309/ 网站添加验证码,主要为防止机 ...
- iOS开发CGRectGetMidX. CGRectGetMidY.CGRectGetMinY. CGRectGetMaxY. CGRectGetMinX. CGRectGetMaxX的使用
[iOS开发]iOS开发CGRectGetMidX. CGRectGetMidY.CGRectGetMinY. CGRectGetMaxY. CGRectGetMinX. CGRectGetMaxX的 ...
- lvs初体验
一.简介 LVS是 Linux Virtual Server 的简称,也就是Linux虚拟服务器.这是一个由章文嵩博士发起的一个开源项目,它的官方网址是http://www.linuxvirtuals ...
- ECSHOP和SHOPEX快递单号查询顺丰插件V8.6专版
发布ECSHOP说明: ECSHOP快递物流单号查询插件特色 本ECSHOP快递物流单号跟踪插件提供国内外近2000家快递物流订单单号查询服务例如申通快递.顺丰快递.圆通快递.EMS快递.汇通快递.宅 ...
- Java学习笔记七:Java的流程控制语句之switch
Java条件语句之 switch 当需要对选项进行等值判断时,使用 switch 语句更加简洁明了.例如:根据考试分数,给予前四名不同的奖品.第一名,奖励笔记本一台:第二名,奖励 IPAD 2 一个: ...
- unity开发c#代码
1.摄像头跟随主角移动,并支持旋转. 开发过程中需要摄像头以一定距离跟随player,同时会进行旋转,属于一种常见的跟随方式. using UnityEngine; using System.Coll ...
- java泛型<? extends E> 有上限通配符与<? Super E>有上限通配符
通配符?,?表示占位,表明将来使用的时候在指明类型 <?>无限定的通配符, 是让泛型能够接受未知类型的数据 <? extends E> 有上限通配符,能够接受指定类及其子类类型 ...
- 为什么我要放弃javaScript数据结构与算法(第二章)—— 数组
第二章 数组 几乎所有的编程语言都原生支持数组类型,因为数组是最简单的内存数据结构.JavaScript里也有数组类型,虽然它的第一个版本并没有支持数组.本章将深入学习数组数据结构和它的能力. 为什么 ...
- shell重温---基础篇(连接数据库)
前几天分享了shell字符串操作,数组操作等,接下来回归到项目,进行数据库操作.按照一般情况来说,shell连接数据库基本上都是DB使用的,因为需要运行大量的sql啊什么的,所以都会封装到shell中 ...