Leetcode 25

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。

如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

进阶

你可以设计一个只使用常数额外空间的算法来解决此问题吗?
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

首先题目很简单。

而且要求空间复杂度为O(1),这就要求递归是不可以的。

题目分析:

* 1->2->3->456
* 2->1->3->456
* 3->2->1->456
* 4->3->2->1

一看是很简单,但是接着我昨天写的代码继续调试,发现还是报错。

其实我整个理念就没搞懂!就是不完全的代码。

于是,我重新分析:

/**
 * 1->2->3->456
 * 2->1->3->456
 * 3->2->1->456
 * 4->3->2->1
 * 得出结论: 每次都是 与prev节点进行交换
 * prev  是 一直都是 1 这个节点
 *  2022年3月13日14:56:35  现在到底需要 start 和 prev 几个节点都是一个问题!
 *  首先 next节点 是肯定要的 如第一步的 2
 *  其次  1会指向 3  所以1也需要1个节点
 *  那么继续看第二步  再来判断1到底需要用什么指针
 *  第二步:  next此时指向3了   3 需要 跟 2交换  而此时的2 上面是没有指针指向的    同时1 也需要指向 4 了。
 *          所以明确了。 在第二步,3已结有指针了, 而1,2都需要指针。 所以在第一步的时候必须有2个指针指向当时的1和2了
 *          假设第一步结束时候是prev指针指向1,start指针指向了2,第二步操作做完:prev指向了1  start指向了3 next指向4 再来看第三步。
 *  第三步:  4(cur)的下一个指向 3(start)   1(prev)的下一个指向5(right)          所以回头第二步:
 *  第二步:  3(cur)的下一个指向 2(start)   1(prev)下一个指向指向4(right)          再回到第一步怎么给prev及 start赋值
 *  第一步:  2(cur)的下一个指向1(则是start) 1(prev)的下一个指向3(rigjt)
 *      所以得出结论: prev和start一开始都指向1
 *      再来看遇到下一个k组的逻辑,因为到现在还不需要用虚拟头结点
 *      图示改为 k=2即可
 * 1->2->3->4
 * 2->1->3->4
 * 2->1->4->3      2022年3月13日16:46:24  原来这里还有1步 3要指向下一个啊
 * 4->3->2->1
 *
 * 第一步: 2(cur)的下一个指向1(则是start) 1(prev)指向3(rigjt)  next指向3 同上
 * 第二步: 得重新赋值 不然3的下一个会指向2 显然不对了。
 * 在第一步结束时候重新赋值: next指向4  prev指向1  start指向3
 *          1(prev)的下一个指向 3
 * 第二步操作: 4(cur)的下一个指向 3(start)  3(prev指向!) 的下一个指向5(rigjt)(如果有)
 *          start  指向 4(start)
 * 这里面区别就出来了。  需要有指针去指向上一个组的最后一个节点
 *         1(prev)的下一个指向 4(start) 很关键!!!
 * 最后得出结论:  start需要一直赋值,用于next的下一个指向它。
 * prev节点也明白了  一直都是每一组的第一个节点了 一直用于指向next的next!
 * 所以总归 需要 3个 指针
 * 最后 初始  弄1个虚拟头结点  (假设)作为上一组的最后一个节点 指向当前(第一组)的头节点
 * dummy.cur = head;
 * 所以最后返回的时候就是dummy.cur 且第一次转换时候 同样做操作 prev等于第一组的头结点
 *  start 是一直变化的
 *
 *  还是一直有问题啊  2022年3月13日16:20:46  这题真得背下来了。  3个数的时候直接不行了  逻辑还是有问题
 *  1->2->3 ->4->5->6  i=0
 *  2->1->3 ->4->5->6  i=1  需要变换start
 *  3->2->1 ->4->5->6  i=2
 *  3->2->1 ->5->4->6  i=3  需要转换staret
 *  3->2->1 ->6->5->4  i=4
 *  3->2->1 ->6->5->4
 *  k个数 只会遍历 k-1次
 */

分析内容如上,得出结论是肯定需要不止2个节点。

但同时也发现我越分析越乱,且非常浪费时间。就算用笔记记下来也不行。

其实我就是分析了下到底需要多少个指针。

分析到了:

先从这步开始: 1->2->3 k=3 要变成 2->1->3

  • 肯定需要1个指针(叫做指针A吧)来指向当前1个节点,然后每次都会指向它的next。
    • 如 1->2->3 k=3 这里面的 2
  • 1也会指向3,所以1也需要1个指针

那此时指针就这2个就够了吗?

这一步: 2->1->3 要交换成为: 3->2->1

则操作是: 3的next要指向21的next则由3指向3原先的next

3就是上面分析到的指针A当前指向的了,暂且不谈。

思考下这步真的需要多少个指针?

1的next都改变了,所以1必须用个指针指向!

3要指向2,2是一个具体的变量吗?可以用之前指针的next啥的来代替吗?答案是不行。

所以2也必须用个指针在第一步去指向了。

重写第一、二步

那么重写第一步和第二步:

第一步: 1->2->3 要变成 2->1->3

第二步: 2->1->3 要变成: 3->2->1

具体流向:

指针 A: 先是2 , step1后是3,最后是null结束遍历

指针 B: 先没有,step1后是2,step2后未知 因为上面null结束遍历了

指针 C: 先没有,step1后是1,step2种指向3原先的next

看下加了第三步后逻辑有没有变化,同时更改名字 k=4

第一步: 1->2->3 ->4 要变成 2->1->3 ->4

第二步: 2->1->3->4 要变成: 3->2->1 ->4

第三步: 3->2->1 ->4 要变成: 4->3->2->1

具体流向:

指针 target(每轮交换后放到第一位的节点的指向):

​ 先是2 , step1后是3,最后是null结束遍历

指针 targetNext(每轮开始时target的下一个指向,用于保留)

​ 先是3 , step1后是4,step2后是null

指针 prev: (实际上始终是第一个节点)

先没有,step1后是1,step2后指向不变,但改变它的next指针的指向。

step3后依旧它的next指向,且依旧是prev.next=targetNext。但step3后prev指针是否改变真的未知

指针 curFirst 每轮结束时候的第一个节点)

先没有,step1后是2,step2后是3,step3后由于结束遍历则未知

带着上面未知的疑问,进行下一步思考。

先放上面的代码:

        /** 每一组的第一个节点 */
        ListNode start = head;
        /** 每一组的依次遍历的节点 从每一组的第二个节点开始直到最后一个节点 */
        ListNode cur = start;
        //还得需要1个变量 不然高不上去
        while (start != null) {
            ListNode target = cur.next;
            ListNode targetNext = target.next;
            target.next = start;
            cur.next =targetNext;
            start = target;
            if (targetNext == null) {
                break;
            }
        }
        return start;

如果要求不是每一个都反转,而是指定前K个反转,怎么做?

所以就需要上面未知的代码了。

先放代码: 其实只是改动跳出的逻辑。

这让我思考了 要不要优化到while里面呢。

        /** 每一组的第一个节点 */
        ListNode start = head;
        /** 每一组的依次遍历的节点 从每一组的第二个节点开始直到最后一个节点 */
        ListNode cur = start;
        //还得需要1个变量 不然高不上去
        while (start != null) {
            ListNode target = cur.next;
            ListNode targetNext = target.next;
            target.next = start;
            cur.next =targetNext;
            start = target;
            if (targetNext == null || i == k-1) {
                break;
            }
        }
        return start;

再然后,如果k个为1组,每组组内反转,这就是这道题目了!

- 2022年3月13日21:38:30
记录下今天怼这题的心路历程吧,希望也能起到写一篇博客彻底记住的效果。
- 2022年3月13日22:42:38
靠,看评论区反转链表,有个那么复杂有啥用呢。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值