• leetcode腾讯精选练习之旋转链表(四)


    旋转链表

    题目:

    给定一个链表,旋转链表,将链表每个节点向右移动 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->NULL, k = 4
    输出: 2->0->1->NULL
    解释:
    向右旋转 1 步: 2->0->1->NULL
    向右旋转 2 步: 1->2->0->NULL
    向右旋转 3 步: 0->1->2->NULL
    向右旋转 4 步: 2->0->1->NULL

    思路:

    再说这个题目的解题步骤之前先说说这个题目的理解,就是链表倒着数k个结点,然后断开k+1和k个结点之间的联接将其分成两个链表。然后将前后两个链表调换一下位置重新连接起来。(当然当k大于链表长度的时候需要取模运算)

    1.计算链表的长度。
    2.定义一个指针pPre指向头结点,移动k步。
    3.定义一个指针pCur指向头结点,同时向前移动pPre和pCur指针直到pPre遍历完整个链表,此时pCur即为倒数第k个结点。
    4.在第k个结点处断开链表,再将前后两个链表交换顺序后重新连接起来。

    代码:

    ListNode* rotateRight(ListNode* head, int k) {
        if (head == NULL || head->next == NULL)
        {
            return head;
        }
        ListNode* pPre = head;
        int count = 0;
        while (pPre != NULL)
        {
            pPre = pPre->next;
            count++;
        }
        ListNode* pCur = head;
        pPre = head;
        for (int i = 0; i < k % count; i++)
        {
            pPre = pPre->next;
        }
        if (pPre != NULL)
        {
            while (pPre->next != NULL)
            {
                pPre = pPre->next;
                pCur = pCur->next;
            }
            pPre->next = head;
            head = pCur->next;
            pCur->next = NULL;
        }
        return head;
    }
    

    改进版:

    ListNode* rotateRight(ListNode* head, int k) {
        if (head == NULL || k == 0)
        {
            return head;
        }
        int count = 1;
        ListNode* p = head;
        while (p->next)
        {
            count++;
            p = p->next;
        }
        int left = count - k % count;
        p->next = head;
        for (int i = 0; i < left; ++i)
        {
            p = p->next;
        }
        head = p->next;
        p->next = NULL;
        return head;
    }
    

    总结:

    1.解题的关键是如何将题目转化为找到倒数第k个结点
    2.另外一个巧妙的地方是循环向前移动两个指针的时候判断的是pPre->next是否为NULL,这样可以将pPre和pCur分别定位到断开链表后的的最后一个结点上,方便断开的链表进行联接。
    3.改进版是我在网上看到别人的思路实现的。首先统计整个链表的长度,同时将一个指针指向链表的最后一个结点,然后将链表首尾联接起来,组成一个环,然后用数学的方法计算出正着数应该移动left步,然后将指向最后一个结点的指针移动left步,最后在这个位置将链表断开即得到结果。

    有时候思路真的就是一层窗户纸

  • 相关阅读:
    【洛谷】P2880 [USACO07JAN]平衡的阵容Balanced Lineup(st表)
    【洛谷】P1052 过河(状压dp)
    【洛谷】P1541 乌龟棋(四维背包dp)
    【BZOJ】4721: [Noip2016]蚯蚓 / 【洛谷】P2827 蚯蚓(单调队列)
    【洛谷】P1064 金明的预算方案(dp)
    【洛谷】P3908 异或之和(异或)
    【洛谷】P2434 [SDOI2005]区间(暴力)
    【洛谷】P2694 接金币(排序)
    【BZOJ】1012: [JSOI2008]最大数maxnumber /【洛谷】1198(线段树)
    【游记】noip2017酱油记
  • 原文地址:https://www.cnblogs.com/zh20130424/p/12203510.html
Copyright © 2020-2023  润新知