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」!

原文地址:https://www.cnblogs.com/seniusen/p/9958388.html

时间: 2024-10-29 02:00:51

LeetCode 61——旋转链表的相关文章

LeetCode 61 旋转链表

链接:https://leetcode-cn.com/problems/rotate-list 给定一个链表,旋转链表,将链表每个节点向右移动 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-

61. 旋转链表

题目描述 给定一个链表,旋转链表,将链表每个节点向右移动 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-

【Leetcode】旋转链表

题目链接:旋转链表 题意:给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. 输入: 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 题解:因为可能出现k > 链表长度的情况,所以

Leetcode:Rotate List 链表旋转

Rotate List Given a list, rotate the list to the right by k places, where k is non-negative. For example:Given 1->2->3->4->5->NULL and k = 2,return 4->5->1->2->3->NULL. 解题分析: 不同于数组旋转,数组可以随机存取,数组的旋转可以巧妙的 分成两两部分递归旋转 对于链表的旋转,实际上

(每日算法)LeetCode --- Reverse Linked List II(旋转链表的指定部分)

Reverse Linked List II(旋转链表的指定部分) Leetcode Reverse a linked list from position m to n. Do it in-place and in one-pass. For example: Given 1->2->3->4->5->NULL, m = 2 and n = 4, return 1->4->3->2->5->NULL. Note: Given m, n sati

61:Rotate List(旋转链表)【链表】【两指针】

题目链接:https://leetcode.com/problems/rotate-list/ /* 题意:给出一个链表,将链表向右旋转k个位置 */ /** *思路:右旋k个位置,相当与将链表从第len-k个位置截断,然后 * 将两截链表交换位置,重新链接成一个链表 * */ struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(NULL) {} }; class Solution { public:

【LeetCode题解】61_旋转链表(Rotate-List)

目录 描述 解法:双指针 思路 Java 实现 Python 实现 复杂度分析 描述 给定一个链表,旋转链表,将链表每个节点向右移动 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-&

[LeetCode] Rotate List 旋转链表

Given a list, rotate the list to the right by k places, where k is non-negative. For example:Given 1->2->3->4->5->NULL and k = 2,return 4->5->1->2->3->NULL. 这道旋转链表的题和之前那道Rotate Array 旋转数组 很类似,但是比那道要难一些,因为链表的值不能通过下表来访问,只能一个一个的

LeetCode --- 61. Rotate List

题目链接:Rotate List Given a list, rotate the list to the right by k places, where k is non-negative. For example: Given 1->2->3->4->5->NULL and k = 2, return 4->5->1->2->3->NULL. 这道题的要求是向右旋转链表k步. 其实就是把链表后面l-k个节点放到前面,可以采用快慢指针处理.不