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 ...
随机推荐
- SpringBoot非官方教程 | 第十三篇:springboot集成spring cache
转载请标明出处: 原文首发于:https://www.fangzhipeng.com/springboot/2017/07/11/springboot13-springcache/ 本文出自方志朋的博 ...
- 更换eclipse字体
eclipse自带的字体非常不好,看的我难受,可能是使用myeclipse习惯了,怎么调节都不好使 最后决定下载一个字体包吧! 字体下载地址如下:http://files.cnblogs.com/ic ...
- python写爬虫的弯路
一开始按照视频上的找了笔趣阁的网站先爬一部小说, 找了<遮天>,但是章节太多,爬起来太慢, 就换了一个几十章的小说. 根据视频里的去写了代码, 在正则表达式哪里出了很大的问题. from ...
- 【杂题总汇】HDU-5215 Cycle
◆HDU-5215◆ Cycle 国庆节集训的第三天……讲图论,心情愉快……刷了一堆水题,不过也刷了一些有意思的题 +传送门+ HDU ▶ 题目 给出一个无向图(无自环,无重边),求该无向图中是否存在 ...
- aix下oracle 12.1.0.2 asmca不能打开的故障
因为要添加一个新的13T磁盘组,所以决定通过asmca处理. 结果输入asmca之后,没有反应,前后两天都是如此. 第三天,IBM的存储工程师已经把心的MPIO挂上,如果还无法操作,只能使用asmcm ...
- vue项目苹果微信端使用this.$router.go(-1)返回上一页,上一页并不会重新加载的问题
window.addEventListener('pageshow', function(e) { // 通过persisted属性判断是否存在 BF Cache if (e.persisted) { ...
- JSP/Servlet开发——第五章 使用分层实现业务处理
1.JNDI(Java Naming and Directory Interface)Java命名和目录接口: ●JNDI:是一个有关应用序设计的 API 为开发人员提供了查找和访问各种命名和目录服务 ...
- BC追踪
项目又要开始改造了,记录一下改造过程中碰到的坑和解决思路,避免以后回头看看自己的笔记都不知道写了什么. (一)敏感信息混淆 (二)活用ComponentScan (三)Swagger配置多项目共用 ( ...
- Java --本地提交MapReduce作业至集群☞实现 Word Count
还是那句话,看别人写的的总是觉得心累,代码一贴,一打包,扔到Hadoop上跑一遍就完事了????写个测试样例程序(MapReduce中的Hello World)还要这么麻烦!!!?,还本地打Jar包, ...
- AB PLC 编程之状态机
AB的程序设计和西门子有点PLC不大一样,在AB中没有RS指令,所以主要用move指令来作步进.今天我们就用Move指令写个AB的程序,和西门子比,有哪些不同. 控制任务 很简单的一个状态机.初始步为 ...