LeetCode92反转部分链表

21 篇文章 0 订阅
11 篇文章 0 订阅
class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
		int len=right-left+1;
        ListNode* pre_head=nullptr;
        ListNode* result=head;
        while(head&&--left){
            pre_head=head;
            head=head->next;
        }
        ListNode* tail=head;
        ListNode* newhead=nullptr;
        ListNode* next=nullptr;
        while(head&&len--){
            next=head->next;
            head->next=newhead;
            newhead=head;
            head=next;
        }
        tail->next=head;
        if(pre_head==nullptr){
            return newhead;
        }else{
            pre_head->next=newhead;
            return result;
        }
    }
};

做题思路

  1. 先计算需要反转的链表长度len=right-left+1
  2. 记录链表的头节点(因为之后的操作,向后遍历会改变head的值,所以要将头节点备份)
  3. 从头开始遍历,得到反转链表头节点的前驱pre和需要开始反转的节点head
  4. 此刻的head是需要反转链表的头节点,也是反转后的尾结点,记录备份。
  5. 从head开始,反转指定长度len,newhead就是反转完成后的头节点,此时head是尾节点的后继,也就是不需要反转的第一个节点
  6. 之后将反转部分的尾结点tail与后面的节点head相连
  7. 根据判断前驱节点是否存在,若不存在(即从第一个节点开始)则返回反转链表头节点newhead,若存在(即开始反转的位置不是第一个节点)则将前驱与反转后的头节点newhead接好,再返回之前备份的头节点result

本题要注意的编程细节

Q:链表反转需要进行几次

A:有几个节点需要反转,就循环几次,也就是说每次循环,反转一个节点

Q:while(len–)和while(–len)有何区别

A:首先循环次数不一样,len–的时候循环进行len次,为len-1到0。–len的时,循环进行len-1次,为len-1到1。本题使用了–left,使得当left为1时,这种情况不会进入到循环之中,循环中的变量自然也不会发生改变。当完成整个操作以后,再判断循环中的值是否变化,就可以分开处理left是否为1的情况

Q:链表反转后,各变量指向什么节点

A:newhead会指向反转后的头节点,若以将head(由next赋值)遍历到结尾为条件循环,此刻的head就会指向null。若链表没有遍历结束,则head指向的是完成遍历后的链表部分的后一个节点,也就是现在的newhead节点在原链表中的后继节点。

Q:链表向后遍历的过程中,哪些变量需要备份

A:头节点head不断后移,题目若要求返回原始链表的头节点,需要将头节点备份

Q:链表进行反转之前,那些变量需要备份

A:原链表的头节点,反转后会变为链表的最后一个节点,所以可以在反转前将其备份tail=head。而循环结束时的head变量是反转完成链表的后继,所以用tail->next=head可以将链表后面连起来

Q:这道题是如何获得链表某个节点的前驱和后继的

A:使用一个循环,–left负责控制循环次数 循环中,将当前节点备份,再指向下一个。所以pre_head是前驱,head是当前的节点。后继是根据反转的过程,得到了未反转的第一个节点,也就是后继。那如何用相同的方法得到后继呢 tail就是当前节点,head就是后继

while(head&&right--){
    tail=head;
    head=head->next;
}

方法二

左神书上有另外一种做法,首先通过一次循环整个链表,获取链表的长度,头节点的前驱和尾节点的后继。还对输入的合法性作出判断。反转对应区间链表后,将前驱和头节点,尾节点和后继连接在一起。

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
		int len=0;
        ListNode* fpre=nullptr;
        ListNode* tpos=nullptr;
        ListNode* node1=head;
        while(node1){
            len++;
            fpre=len==left-1?node1:fpre;
            tpos=len==right+1?node1:tpos;
            node1=node1->next;
        }
        if(left<1||left>right||right>len){
            return head;
        }
        node1=fpre==nullptr?head:fpre->next;
        ListNode* node2=node1;
        ListNode* newhead=nullptr;
        ListNode* next=nullptr;
        while(node1!=tpos){
            next=node1->next;
            node1->next=newhead;
            newhead=node1;
            node1=next;
        }
        node2->next=tpos;
        if(fpre==nullptr){
            return newhead;
        }else{
            fpre->next=newhead;
            return head;
        }
    }
};

代码细节

Q:获取链表的长度和指定节点的前驱后继

A:判断len与left-1或者right+1是否相等,若相等则说明正好在对应节点上,若不相等,则保持原来的值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Rust 是一种现代的编程语言,特别适合处理内存安全和线程安全的代码。在 LeetCode 中,链表是经常出现的题目练习类型,Rust 语言也是一种非常适合处理链表的语言。接下来,本文将从 Rust 语言的特点、链表的定义和操作,以及 Rust 在 LeetCode链表题目的练习等几个方面进行介绍和讲解。 Rust 语言的特点: Rust 是一种现代化的高性能、系统级、功能强大的编程语言,旨在提高软件的可靠性和安全性。Rust 语言具有如下几个特点: 1. 内存安全性:Rust 语言支持内存安全性和原语级的并发,可以有效地预防内存泄漏,空悬指针以及数据竞争等问题,保证程序的稳定性和可靠性。 2. 高性能:Rust 语言采用了“零成本抽象化”的设计思想,具有 C/C++ 等传统高性能语言的速度和效率。 3. 静态类型检查:Rust 语言支持静态类型检查,可以在编译时检查类型错误,避免一些运行时错误。 链表的定义和操作: 链表是一种数据结构,由一个个节点组成,每个节点保存着数据,并指向下一个节点。链表的定义和操作如下: 1. 定义:链表是由节点组成的数据结构,每个节点包含一个数据元素和一个指向下一个节点的指针。 2. 操作:链表的常用操作包括插入、删除、查找等,其中,插入操作主要包括在链表首尾插入节点和在指定位置插入节点等,删除操作主要包括删除链表首尾节点和删除指定位置节点等,查找操作主要包括根据数据元素查找节点和根据指针查找节点等。 Rust 在 LeetCode链表题目的练习: 在 LeetCode 中,链表是常见的题目类型,而 Rust 语言也是一个非常适合练习链表题目的语言。在 Rust 中,我们可以定义结构体表示链表的节点,使用指针表示节点的指向关系,然后实现各种操作函数来处理链表操作。 例如,针对 LeetCode 中的链表题目,我们可以用 Rust 语言来编写解法,例如,反转链表,合并两个有序链表,删除链表中的重复元素等等,这样可以更好地熟悉 Rust 语言的使用和链表的操作,提高算法和编程能力。 总之,在 Rust 中处理链表是非常方便和高效的,而 LeetCode 中的练习也是一个非常好的机会,让我们更好地掌握 Rust 语言和链表数据结构的知识。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值