2021-06-28旋转链表

leetcode每日一题之旋转链表

**题目链接:**https://leetcode-cn.com/problems/rotate-list/

题目描述:

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

例子:

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

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

解法:

以示例1为例 1->2->3->4->5,k=2,那么移动完就是:
4->5->1->2->3
移动一次的时候是 5->1->2->3->4,移动两次就是4->5->1->2->3。
看出什么端倪了吗?
关键点就是k,如果移动一次就相当于将倒数第一个元素1移到链表开头,如果移动两次就相当于将倒数第二和倒数第一个元素2和1移动到链表开头。
所以这题的关键是要找到倒数第k个节点。
在这之前我们还需要处理一些细节:
当k等于链表总长时,就相当于移动0次,也就是啥也不用做直接返回就行了。如果k>链表总长,比如k=7时,结果仍然是5->4->3->2->1。
所以我们要先对k取模,取模后的k范围应该是:
1<=k<=链表总长-1
找到倒数第k个节点4,然后将链表的尾部指向开头
在这里插入图片描述

再将节点4前面一个3的next指向null,一定要断开,否则链表就成环状啦
在这里插入图片描述

最后返回新的头结点4就可以了
在这里插入图片描述

代码如下:

    public ListNode rotateRight(ListNode head, int k) {
            if (head == null || k <= 0) {
                return head;
            }
            //创建一个特殊节点,快指针,慢指针,统计节点个数的cur
            ListNode p = new ListNode(-1);
            p.next = head;
            ListNode cur = p;
            ListNode low = p;
            ListNode fast = p;
            int n = 0;
            //统计链表个数
            while (cur.next != null) {
                cur = cur.next;
                ++n;
            }
            //边界条件不用忘记处理了
            //其实有这段最上面的head==null可以省略
            if (n == 0 || k % n == 0) {
                return head;
            }
            //还有一个边界条件不要忘了,k可能大于n,所以要取模
            k = k % n;
            //快指针先移动k步
            while (fast.next != null && k > 0) {
                fast = fast.next;
                --k;
            }
            //快指针,慢指针一起移动,找到需要切割的点
            while (fast.next != null) {
                low = low.next;
                fast = fast.next;
            }
            //改变链表的指向关系,注意这里的步骤不要乱了
            //先让fast节点指向head(也就是p.next)
            //再是head(也就是p.next)指向low的下一个节点
            //这两步如果弄反了就会出现节点丢失了
            //最后不要忘记将low.next置空
            fast.next = p.next;
            p.next = low.next;//为了返回使用,结合着图看
            low.next = null;
            return p.next;
        }
    

=======================================================================================

下面是看懂之后自己写的一遍代码:

    public ListNode rotateRight2(ListNode head, int k) {
            //
            if (head == null || head.next == null || k <= 0) {
                return head;
            }
            //首先统计链表个数,定义一个假节点
            ListNode dummy = new ListNode(-1);
            dummy.next = head;
            ListNode p = dummy;
            //快慢指针是为了查找倒数第k个节点
            ListNode slow = dummy;
            ListNode fast = dummy;
            int n = 0;//链表元素个数
            while (p.next != null) {
                p = p.next;
                n++;
            }
            if (n == 0 || k % n == 0) {
                return head;
            }
    //        k = n % k;这里自己写的时候出现了误解
            k = k % n;//k可能大于n
            //先让块指针走k步
            while (fast.next != null && k > 0) {
                fast = fast.next;
                k--;
            }
            while (fast.next != null) {
                slow = slow.next;
                fast = fast.next;
            }
            fast.next = dummy.next;
            dummy.next = slow.next;
            slow.next = null;
            return dummy.next;
        }

总之,这个题目还是挺好的,因为我不喜欢动手,因此又是没有想起来,只是用到了之前的找倒数第k个节点,相当于又复习了一遍。

参考:配图以及讲解都来自公众号大话算法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值