Day3-leetcode92、25

一、解题过程

leetcode92.反转链表 II

(1)题目描述

题目链接如下:

leetcode92.反转链表||https://leetcode.cn/problems/reverse-linked-list-ii/submissions/386694465/

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

示例 1:

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

示例 2:

输入:head = [5], left = 1, right = 1
输出:[5]

提示:

  • 链表中节点数目为 n
  • 1 <= n <= 500
  • -500 <= Node.val <= 500
  • 1 <= left <= right <= n

做题分析:

用自己的话解释题意

在一个给定的链表里,把[left,right]的区间里的链表反转过来,并且重新连接到链表里。


ok

开始思考解决方法:

刚开始的第一印象是昨天的反转链表的题,即leetcode206.反转链表题解

但是

在写的过程中,发生了亿点事情。

链表的题细节方面我觉得不是很好处理。

相比于leetcode206.反转链表题解不同的是:

1、此题我们需要对一个链表片段进行反转。

2、我们对片段处理完了之后,还需要将其重新连接到链表之中。

3、如何在一个反转部分的链表里准确找到新的头结点。

针对于以上问题:

我们分步骤解决

首先第一个问题,可以针对于需要处理的片段,通过确定待处理链表的长度和位置,来实现精准局部反转。

具体实现即for(int i=0;i<right-left+1;i++)这样一个循环,确定具体反转操作需要进行多少次。

第二个问题如何把处理好的链表连接回去

我们可以记录一下在[left,right]区间外紧邻left和right的那两个元素因为这两个元素的链没有改变 ,所以直接改next值即可。

我们具体实现时用到的是:p0作为left左边的元素指针。因为反转之后,我们需要把p0的next连接到末尾的pre位置。同时把p0->next的next和区间外右边第一个元素相连。

如图所示:

第三个问题:

因为我们在这个更改过程中如果涉及到了初始head的变化,那我们头指针位置就会发生改变。

新的位置则是我们改变的链表片段的末尾置。那我们如何解决呢?

这里用到了一个虚拟指针vir

我们把虚拟指针指向head。那么无论是head改变与否,p0是在哪里。我们的vir一直没有改变,那么Vir的next一直是头节点。

那么具体实现是在以下。

代码片段:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        ListNode *vir=new ListNode(0,head),*p0=vir;//vir是一个虚拟节点,方便后期寻找头节点,p0则是一个left左边的一个邻接指针。
        ListNode *cur,*pre,*nxt;
        //确定left前的位置。即p0;
        for(int i=0;i<left-1;i++)p0=p0->next;
        
        cur=p0->next;
        pre=p0;
        //经典的反转算yin法
        for(int i=0;i<right-left+1;i++){
            nxt=cur->next;
            cur->next=pre;
            pre=cur;
            cur=nxt;
        }
        //将反转后的片段连到原先的链表里
        p0->next->next=cur;
        p0->next=pre;
        return vir->next;
    }
};


25.K 个一组翻转链表

(1)题目描述

题目链接如下:

力扣25. K 个一组翻转链表https://leetcode.cn/problems/reverse-nodes-in-k-group/description/

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

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例 1:

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

示例 2:

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

提示:

  • 链表中的节点数目为 n
  • 1 <= k <= n <= 5000
  • 0 <= Node.val <= 1000

做题分析:

用自己的话解释题意:

把一个链表,每k个一组进行反转,最后剩下的如果不到k个,最后这几个则无需进行反转。


开始思考解决方法:

这一题,其实就是上一题(力扣92)的plus版本

但终究来说是同源

所以我们开始找不同

这一题的反转次数不再是1次了。而是变成多次-----那我们相对应的只要把计算出来有多少次,并且认为每一次都是一个上一题(力扣92)。那这样就可以啦。

具体细节是看以下代码实现:

讲解的话和上面一样,可以重新阅读一下上面的部分

代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode *reverseKGroup(ListNode *head, int k) {
        int n=0;
        for (ListNode *cur=head;cur;cur=cur->next)++n; // 统计节点个数
        ListNode *vir=new ListNode(0, head), *p0=vir;
        ListNode *pre=NULL,*cur=head,*nxt;
        for (int i=1;i<=n/k;i++){
            for (int i=0;i<k;++i) { //同92题片段的反转
                nxt=cur->next;
                cur->next=pre;
                pre=cur;
                cur=nxt;
            }
            nxt=p0->next;
            p0->next->next = cur;
            p0->next=pre;
            p0=nxt;
        }
        return vir->next;
    }
};

二、总结及计划

今天的题,怎么说呢

全是链表

原本最开始我是直接做的力扣25的那一道,但是我做着做着发现

就是在思考以及写程序的过程中出现了很多不足。

发现自己思考的不是很完善,链表的细节处理还是很值得自己拿起来笔仔细推敲推敲的。

也推荐一下今天下午我在学习的过程中看的一个b站up主讲的课:反转链表又写错了?一个视频讲透!【基础算法精讲 06】反转链表 | 反转链表II | K个一组翻转链表 | 力扣 LeetCode 算法面试题_哔哩哔哩_bilibili

今天的收获很大,非常棒哈。继续努力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值