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——旋转链表的更多相关文章

  1. Java实现 LeetCode 61 旋转链表

    61. 旋转链表 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: 1->2->3->4->5->NULL, k = ...

  2. leetcode 61. 旋转链表

    题目描述: 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: 1->2->3->4->5->NULL, k = 2 输 ...

  3. LeetCode 61——旋转链表(JAVA)

    给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: 1->2->3->4->5->NULL, k = 2 输出: 4-& ...

  4. LeetCode 61. 旋转链表(Rotate List)

    题目描述 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: 1->2->3->4->5->NULL, k = 2 输出 ...

  5. LeetCode:旋转链表【61】

    LeetCode:旋转链表[61] 题目描述 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: 1->2->3->4->5- ...

  6. leetcode网解题心得——61. 旋转链表

    目录 leetcode网解题心得--61. 旋转链表 1.题目描述 2.算法分析: 3.用自然语言描述该算法 4.java语言实现 5.C语言实现 leetcode网解题心得--61. 旋转链表 1. ...

  7. 【LeetCode】61. 旋转链表

    61. 旋转链表 知识点:链表: 题目描述 给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置. 示例 输入:head = [1,2,3,4,5], k = 2 输出:[4 ...

  8. 61. 旋转链表-leetcode

    给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: 1->2->3->4->5->NULL, k = 2 输出: 4-& ...

  9. leetcode刷题-61旋转链表

    题目 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: 1->2->3->4->5->NULL, k = 2输出: 4 ...

随机推荐

  1. HDU 1399 Starship Hakodate-maru(暴力搜索)

    传送门: http://acm.hdu.edu.cn/showproblem.php?pid=1399 Starship Hakodate-maru Time Limit: 2000/1000 MS ...

  2. 上传文件,经过Zuul,中文文件名乱码解决办法

    转载请标明出处: http://blog.csdn.net/forezp/article/details/77170470 本文出自方志朋的博客 问题描述 在项目中又一个上传文件的oss服务,直接调用 ...

  3. SpringBoot非官方教程 | 第二十六篇: sprinboot整合elk,搭建实时日志平台

    转载请标明出处: 原文首发于https://www.fangzhipeng.com/springboot/2017/07/11/sprinboot25-elk/ 本文出自方志朋的博客 这篇文章主要介绍 ...

  4. Struts2知识点小结(三)--值栈与ognl表达式

    1.问题一 : 什么是值栈 ValueStack        回顾web阶段 数据交互问题?        客户端提交数据  到  服务器端    request接受数据+BeanUtils实体封装 ...

  5. HTML5新标签的兼容性处理

    普通浏览器 普通不支持HTML5新标签的浏览器 -- 能正常解析,但会当初成 inline 元素对待 在不支持HTML5新标签的浏览器里,会将这些新的标签解析成行内元素(inline)对待,所以我们只 ...

  6. 【前行&赛时总结】◇第4站&赛时9◇ CF Round 513 Div1+Div2

    ◇第4站&赛时9◇ CF Round 513 Div1+Div2 第一次在CF里涨Rating QWQ 深感不易……作blog以记之 ( ̄▽ ̄)" +Codeforces 的门为你打 ...

  7. Centos防火墙的配置

    Selinux的三种模式:enforcing,passive,disable 临时更改模式:setengorce 1|0        1:enforcing,   0:passive [root@C ...

  8. 通过swagger下载的文件乱码解决方法,求解

    这里的数据显示 点击Download Templates下载之后是显示一个response流都不是一个xlsx文件 这个是由什么原因造成的,求解?

  9. python-映射·字典

    1.创建字典:字典由键值对组成,每个键值对就是字典的一个元素,键值对之间用分号(:)隔开,元素之间用逗号(,)隔开.字典中的键必须是唯一 且不可变得(不可以是列表或者字典).字典中的元素是无序的. d ...

  10. P1049 装箱问题

    装箱问题 题目描述 有一个箱子容量为V(正整数,0<=V<=20000),同时有n个物品(0<n<=30,每个物品有一个体积(正整数). 要求n个物品中,任取若干个装入箱内,使 ...