61 旋转链表(分析、递归)

1. 问题描述:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/rotate-list

2. 思路分析:

① 题目还是比较好理解的,除了从题目中得到旋转链表的元素的特点之外,我们还可以仔细观察题目中给出的测试用例,以便得到旋转链表的元素是怎么样组成的,从测试用例可以知道旋转之后的链表的特点为:

1)之前的尾节点连接上了链表之前的头结点

2)因为是移动k个元素所以我们需要遍历链表找到旋转之后链表的头结点,并将新链表的头结点的上一个节点置为null即可,这个也很好理解,遍历元素的位置 + k假如等于了整个链表的长度那么这个位置就是新链表的头结点,而头结点的上一个节点next指针域肯定是null,所以根据这个关系我们可以找到新链表头结点的上一个节点,并且将上一个节点置为null即可完成

所以对应的操作:遍历整个链表找到最后一个节点,将最后一个节点的指向链表头结点,这个时候形成了一个环,然后我们再遍历链表找到链表移动k个位置的节点,其实我们是可以先找到新链表的头结点的上一个节点,先保存上一个节点的next也就是新链表的头结点,然后上一个节点的next指针域置为空即可

② 除了使用迭代的方法,对于链表的大部分操作也是可以使用递归来解决的,使用递归的话需要使用全局变量来保存链表的尾节点,在递归的过程中找到新链表的头结点,并且在层层返回的时候将新链表的头结点的上一个节点置为空,递归的话处理比迭代要复杂一点,其中主要是三个操作:找到尾节点,找到新链表的头结点,将新链表的头结点的上一个节点置为空,其实这些关系与细节结合具体的例子非常好了,我在写代码的时候都是结合简单的例子来写出其中的关系的

3. 代码如下:

递归代码:

class Solution {
    int nodeCount;
    ListNode newh;
    ListNode tail;
    ListNode h;
    public ListNode rotateRight(ListNode head, int k) {
        /*不移动或者当前的节点本身为空直接返回head*/
        if (k == 0 || head == null) return head;
        h = head;
        recursion(head, k, 0);
        /*移动的步数为节点数量的整数倍的时候直接返回原来的根节点*/
        if (k % nodeCount == 0) return h;
        tail.next = h;
        return newh;
    }

    private void recursion(ListNode head, int k, int count) {
        if (head == null) return;
        ++nodeCount;
        recursion(head.next, k, count + 1);
        if (tail == null && head.next == null) tail = head;
        /*在递归返回的时候根据全局变量的值计算出对应的新根节点的位置在哪里*/
        /*分为两种情况来处理*/
        if (k > nodeCount) {
            /*需要注意节点的关系*/
            if (count + 1 == nodeCount - k % nodeCount) head.next = null;
            if (count + k % nodeCount == nodeCount) newh = head;
        }else {
            /*将next指针域置为空*/
            /*下面两个节点结果相差为1*/
            if (count + 1 == nodeCount - k) head.next = null;
            if (count + k == nodeCount) newh = head;
        }
    }
}

迭代代码:

class Solution {
     public ListNode rotateRight(ListNode head, int k) {
        /*不移动所以直接返回head*/
        if (k == 0 || head == null) return head;
        ListNode p = head;
        ListNode curHead = null;
        int totalNodes = 0;
        /*首先是需要找到链表的尾节点*/
        while (p.next != null){
            p = p.next;
            ++totalNodes;
        }
        ++totalNodes;
        //相当于不移动
        if(k % totalNodes == 0) return head;
        /*现在是形成了一个环*/
        p.next = head;
        p = head;
        int i = 1;
        k = k < totalNodes ? k : k % totalNodes;
        while (i + k < totalNodes){
            p = p.next;
            ++i;
        }
        curHead = p.next;
        p.next = null;
        return curHead;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值