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 ...
随机推荐
- 【题解】洛谷P2914[USACO08OCT]断电Power Failure
洛谷P2914:https://www.luogu.org/problemnew/show/P2914 哇 这题目在暑假培训的时候考到 当时用Floyed会T掉 看楼下都是用Dijkstra 难道没有 ...
- LINQ to XML简介
我们的配置文件使用XML存储信息.ADO.NET的DataSet(利用扩展方法)可以方便的将数据保存(或加载)为XML..NET特有的XML API,如XmlReader/XmlWriter类.微端提 ...
- checkbox 全选
<template> <div class="hello"> <table> <tr> <th><input ty ...
- python之selectors
selectors是select模块的包装器,ptython文档建议大部分情况使用selectors而不是直接使用selectors 样例代码如下 # -*- coding: utf-8 -*- __ ...
- 搜索框反射型xss问题解决(网站开发)
什么是反射型XSS XSS又叫CSS (Cross Site Script) ,跨站脚本攻击.它指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的h ...
- VMware虚拟机下载与安装(内附密钥)
VMware下载与安装 一.虚拟机的下载 1.进入VMware官网,点击左侧导航栏中的下载,再点击图中标记的Workstation Pro,如下图所示. 2.根据操作系统选择合适的产品,在这里以Win ...
- Hello,移动WEB—Viewport_Meta标签
二 Viewport meta标签: 语法:<meta name="viewport" content="name=value, name=value" ...
- JS高级. 06 缓存、分析解决递归斐波那契数列、jQuery缓存、沙箱、函数的四种调用方式、call和apply修改函数调用方法
缓存 cache 作用就是将一些常用的数据存储起来 提升性能 cdn //-----------------分析解决递归斐波那契数列<script> //定义一个缓存数组,存储已经计算出来 ...
- less学习三---父选择器
引用父选择器需要用到“&”符号 &运算符表示嵌套规则的父选择器,并且在修改类或伪类选择器的应用中非常普遍 ul{ li{ &:nth-child(2) a { color: r ...
- jQuery(二)事件
鼠标事件: click dblclick mouseenter:鼠标进入 mouseleave:鼠标离开 hover:鼠标悬停 <!DOCTYPE html> <html> & ...