每日一题(6)——数据结构(LeetCode)

本文分享了如何解决LeetCode上的旋转链表问题,通过两种不同的Java代码实现,分别是直接旋转和利用链表长度优化。解题思路强调了减少遍历次数以优化时间复杂度,从O(n^2)降低到O(n)。同时分析了两种方法的优缺点,适合提升数据结构和算法理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

每日一题(6)——数据结构(LeetCode)

题目

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。
示例1:
在这里插入图片描述

输入:head = [1,2,3,4,5], k = 2
输出:[4,5,1,2,3]

示例2:
在这里插入图片描述

输入:head = [0,1,2], k = 4
输出:[2,0,1]

代码

代码1:

    public ListNode rotateRight(ListNode head, int k) {
        if (head == null||head.next==null) {
            return head;
        }
        ListNode curNext = head.next;
        while (curNext.next != null) {
            curNext = curNext.next;
        }
        curNext.next = head;
        for (int i = 0; i < k; i++) {
            ListNode cur = head;
            while (cur.next != curNext) {
                cur = cur.next;
            }
            head = curNext;
            curNext = cur;
        }
        curNext.next = null;
        return head;
    }

代码2:

    public ListNode rotateRight(ListNode head, int k) {
        if (head == null || head.next == null) {
            return head;
        }
        int count = 1;
        ListNode cur = head;
        while (cur.next != null) {
            cur = cur.next;
            count++;
        }
        cur.next = head;
        for (int i = 0; i < count - (k % count); i++) {
            cur = cur.next;
            head = head.next;
        }
        cur.next = null;
        return head;
    }

解题思路

我们可以发现这种题目节点的个数,val没有发生改变,改变的只是连接的位置,而且是相邻节点之间依次发生变化,因此我们可以将首尾相连,然后返回移动之后的头节点,并将环链表变为单链表。这是我们的大体思路。我们先看第一种解法。
代码1:
首先我们实例化curNext这个节点,这个节点先遍历到最后一个节点,然后将curNext的next改为head,这样单链表就形成了环。像这样:
在这里插入图片描述
这时候,进入循环,实例化一个节点cur,遍历链表,直到cur是curNext的前驱节点也就是“0x456”,这个位置。然后让head指向curNext,让curNext指向cur。像这样:
在这里插入图片描述
这样就完成了一次的向右移动,循环k次(假设k为2),跳出循环后,将curNext的next赋值为null(将环变成单链表),最后返回head节点,问题解决。
在这里插入图片描述
但是如果我们将代码1提交到LeetCode中去,会发现报出时间超时,这是因为时间复杂度大了,我们可以看到这种解题,再循环中还需要遍历链表,找出curNext的前驱节点,然后再往前移,这样就导致时间复杂度为O(n2),我们再来看代码2的解题思路。
代码2:
代码1中我们可以看到head和curNext是往后移动,这样就导致要找到前驱节点。那么能不能让head往前移动呢?当然可以,但是往前移动就不单单是k次循环,是与链表的长度有关。
假设链表长度count为5。
当k为1时,head需要移动4次,也就是循环4次。
当k为2时,head需要移动3次,也就是循环3次。
……
当k为4时,head需要移动1次,也就是循环1次。
得到结论:循环次数 = count - k。
如果是这样,那么我们又掉进了坑里面了,为什么?我们k的取值都是小于5的,到那时我们知道k是可以大于5的,如果大于5,那么循环次数就为负数了,这显然不可能,那么我们发现以5作为一个周期,如果大于5,只要k对5取余,然后再用链表长度count减去余数就可以解决了。所以最后得出:循环次数 = count -(k%count)(k<=5也是成立的)。
得到了循环次数,那么在一次循环中,我们只要让head往前移动一个节点,让cur再前移动一个节点,最后跳出循环,将cur.next赋值为null,返回head,问题解决。代码2就减少了遍历链表的操作,这样时间复杂度也相应的变成了O(N)。
好了,这次的每日一题分享就到这里,如果对你有所帮助,欢迎点赞收藏,发现问题或者提出建议,欢迎各位私信,谢谢大家。最后附上今日题目链接。
附:LeetCode61题——旋转链表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Solitudefire

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值