算法练习day4

news2024/9/24 1:18:27

前言

中间个人原因断了很久,现在回来继续。。。。

两两交换链表中的节点

代码随想录 两两交换链表中的节点

24. 两两交换链表中的节点 - 力扣(LeetCode)

(用时:0.3小时)

思路

这道题的思路其实很简单,两两节点交换,注意在交换前提前保存好可能会断链的节点即可。

同时也需要注意节点交换的顺序问题,其他的就没什么。

至于递归实现,后续有时间再说吧。。。

代码实现

/// <summary>
/// 三指针交换
/// </summary>
/// <param name="head"></param>
/// <returns></returns>
public ListNode SwapPairs(ListNode head)
{
    ListNode visHeadNode, tempNode, curNode;
    visHeadNode = new ListNode();
    visHeadNode.next = head;
    curNode = visHeadNode;
​
    while(curNode.next!=null && curNode.next.next!=null)
    {
        tempNode = curNode.next.next;
​
        curNode.next.next = tempNode.next;
        tempNode.next = curNode.next;
        curNode.next = tempNode;
​
        curNode = tempNode.next;                
    }
​
    return visHeadNode.next;
}

删除链表的倒数第N个节点

代码随想录 删除链表的倒数第N个节点

19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

(用时:0.5小时)

思路

这道题用快慢指针法,即只遍历一次就找到倒数第n个节点。(假设链表长度为N,那么就是找到正数第N-n个节点)

  • 快指针与慢指针始终相差N-n+1个节点。

  • 快指针向前探索,直到到达链表结尾(结尾节点的next为null)

  • 慢指针先和快指针拉开N-n+1个节点的距离,随后跟随着快指针的脚步向后遍历即可。

  • 两个指针相差N-n+1,是因为在去除倒数第n个节点(正数第N-n个节点)时,需要通过其前驱节点,因此需要少前进一步。

  • 需要找到并让fastNode指向第N-n+1个节点,也可以说fastNode需要先走n+1步

易错/错误点

本题思路其实不难,但在临界值方面和容易出错,因此需要格外注意。自己也是在这里踩坑了。。。

易错或者说比较重要的点有几个:

  1. 赋初始值时,fastNode和slowNode的初始值究竟是什么好呢?

  2. 第一个while的判断条件中,n的条件是n>=0还是n>0呢?

  3. 第二个while的判断条件

个人的理解如下:

  • n的判断条件

    fastNode需要在第一个while中与slowNode拉开n个节点的距离。 对于n的判断条件,n每循环一次就-1。当n=0时,fastNode走了n步,fastNode需要先走n+1步,因此while需要再循环一次,n=0成立。

  • fastNode的初始值

    fastNode要么是visHeadNode,要么是visHeadNode.next。visHeadNode.next就是链表真实头节点。

    此时我们需要明白一个问题,先做个假设,假设链表有3个节点,让slow和fast分别在链表的头和尾处:

    微信图片_20240507211111

    可以发现,链表长度为3,而slow和fast之间相隔1个节点。这说明链表的头和尾之间是相隔n-2个节点。

    回到fastNode的初始值问题,假设题目的链表就是如上图所示,如果需要删除的是倒数第3个节点(即真实头节点): ​ 当fastNode=visHeadNode.next(即fastNode=真实头节点)。当n自减到1时,fastNode已经指向了末尾。此时固然可以让第一个while里多一个fast.next!=null的判断条件,第一二个while均可正确通过。但是需要注意最后的移除节点步骤,slowNode是需要移除节点的前驱节点,按照这个逻辑,我们将把第一个节点删除,它是链表的倒数第2个,这与我们的目标不符,这里就出了问题。 ​ 因此,我们需要让fastNode的初始值为visHeadNode。

  • slowNode的初始值

    slowNode在第二个while循环中才需要让其开始遍历,在此之前是没有更改的。slowNode的初始值需要和fastNode一样,因为都是从“头”开始遍历嘛。

  • 第二个while中的判断条件

    第二个while的逻辑是让slow和fast向前遍历,直到fastNode找到链表尾节点。链表尾节点的条件是fastNode.next!=null,因此这就是判断条件。

代码实现

快慢指针法:

/// <summary>
/// 快慢指针法
/// </summary>
/// <param name="head"></param>
/// <param name="n"></param>
/// <returns></returns>
public ListNode RemoveNthFromEnd(ListNode head, int n)
{
    ListNode visHeadNode, fastNode, slowNode;
    visHeadNode = new ListNode();
    visHeadNode.next = head;
    fastNode = visHeadNode;
    slowNode = visHeadNode;
​
    while (n > 0)
    {
        fastNode = fastNode.next;
        n--;
    }
​
​
    while(fastNode.next!=null)
    {
        slowNode = slowNode.next;
        fastNode = fastNode.next;
    }
​
    slowNode.next = slowNode.next.next;
    return visHeadNode.next;
}

链表相交

代码随想录 面试题 20.07链表相交

面试题 02.07. 链表相交 - 力扣(LeetCode)

(用时:3小时)

思路

本道题刚开始只想到双重循环的暴力搜索方法,后来看了卡哥的视频后,原来还可以通过链表长度来实现。

此外,在网站上看C#题解样例时,看到了另外一个很有意思的解法。自己画图后发现,这位大佬用的是环形链表的方法。

链表长度同步移动法

两链表若有相交,那么从相交的节点开始往后应均为一样。

假设较短的链表从头节点开始便以相交,那么较短链表长度即为相交链表可能的最大长度,这样能一定程度上降低时间复杂度。

总结来说,首先需要得到较短链表的长度,接着让较长链表的指针从与较短链表长度一样的节点开始,最后让两个链表的指针同时向后探索扫描,当指向同一个节点时便找到了相交链表的头节点。

错误

看是看懂了,但是在写的时候还是犯了一些错误:

  1. 指针遍历写错了(这个错误只能说是大晚上脑子不清醒吧。。。自己都无语了。。)

  2. 求得短的链表长度后,只动长链表的指针即可。

反思后的理解如下:

  • 求得短的链表长度后,只动长链表的指针即可。

    这里刚开始让两个指针都在动,导致了短链表的指针到了末尾甚至空值引用了。。。 两个链表的可能的相交节点位置是不固定的。求得短的链表长度后,让长的链表的指针指向开头即可,短链表的指针无需动。

合并链表追逐法

这个追逐法其实就是将两个链表首尾连在一起,如果有环,说明他们有相交。

此时这个问题就从是否相交转化成了,这一大条链表,首尾相接后,是否还有更小的环。

接着用环形链表的特性:两个指针在环形链表中始终向前跑,若环形链表有环,那么两个指针一定会相遇。(后面一题的环形链表中,卡哥有讲原理)

本道题中,两个指针没有快慢之分,那么他们一定会在两个链表开始相交的节点上相遇。

image-20240508112919035

重点

此时有个很重要的问题,如果链表没有相交,那怎么判断他们没有相交?(即怎么让循环停下来)

两个链表根据他们的长度分为长度相等和长度不等的情况

  • 长度相等:当他们共同到尾节点,他们或者他们的next均会等于null,此时就是终止条件。

  • 长度不相等:两个指针走过的节点一个长一个短,那么让走的长一点的指针走一遍短的路、让走的短一点的指针走一遍长的路,

他们会同时走到对方链表的尾节点,他们或者他们的next均会等于null,此时就是终止条件。

代码实现

链表长度同步移动法:

/// <summary>
/// 链表长度同步移动法
/// </summary>
/// <param name="headA"></param>
/// <param name="headB"></param>
/// <returns></returns>
public ListNode GetIntersectionNode(ListNode headA, ListNode headB)
{
    ListNode curA = headA,curB = headB;
    int lenA = 0, lenB = 0;
​
    //得到较短链表的长度
    while (curA!=null)
    {
        lenA++;
        curA = curA.next;
    }
    
    while(curB!=null)
    {
        lenB++;
        curB = curB.next;
    }
​
    //设置较长链表的指针初始值
    curA = lenA > lenB ? headA : headB;
    curB = lenA > lenB ? headB : headA;
    for (int i=0;i<Math.Abs(lenA-lenB);i++)
    {
        curA = curA.next;
    }
​
    //两个链表的指针同时向后探索扫描
    while (curA!=null)
    {
        if (curA==curB)
        {
            return curA;
        }
        curA = curA.next;
        curB = curB.next;
    }
    return null;
}

合并链表追逐法:

/// <summary>
/// 合并链表追逐法
/// </summary>
/// <param name="headA"></param>
/// <param name="headB"></param>
/// <returns></returns>
public ListNode GetIntersectionNode2(ListNode headA, ListNode headB)
{
    ListNode curA = headA, curB = headB;
​
    while(curA!=curB)
    {
        curA = curA == null ? headB : curA.next;
        curB = curB == null ? headA : curB.next;
    }
​
    return curA;
}

环形链表

代码随想录 环形链表II

142. 环形链表 II - 力扣(LeetCode)

(用时:2小时)

思路

前面链表相交也有涉及到环形链表的知识。前面理解了这里其实不是很难。

要证明链表是否有环,和前面一样提到的一样:两个指针在环形链表中始终向前跑,若环形链表有环,那么两个指针一定会相遇。

这里卡哥推导证明环形链表快慢指针如何相遇、两指针如何找入口才是重点难点。(时间问题推导就略过了,二刷时再自己推导)

错误

写的过程中犯了一些错误:

  1. fastNode和slowNode的初始值。

  2. while中,指针的遍历和if判断的前后位置。

  3. 为什么第二个while要嵌套在第一个while里面

个人理解如下:

  • fastNode和slowNode的初始值

    最近写的题中,初始值的问题总是会遇到问题。fast和slow两个指针都是从head头节点开始的,在赋初始值时,一般都是按照这个思路来,无需多想让后面的逻辑方便。当后续需要再回头修改至逻辑通畅即可。

  • while中,指针的遍历和if判断的前后位置

    (这里其实也不是说犯错了,是自己有疑惑去尝试出来后得出来的想法。)两个指针的初始值都是head,如果不先走,那么刚开始就已经是指向同一个节点了。

  • 为什么第二个while要嵌套在第一个while里面

    最开始自己的思路: 在第一个while中,快慢指针向前探索,若两者相遇了,则说明有环。若没相遇,fastNode到链表末尾了,则没有环,返回null。 接着fastNode指向链表头节点,在第二个while中,让两个指针以同样的速度向前遍历,相遇的节点即为环形的入口。

    测试后发现,示例1和3并不能通过,能力原因暂时也没找到原因。。。当时写的代码保留了下来:

    public ListNode DetectCycle(ListNode head)
    {
        ListNode fastNode = head, slowNode = head;
    ​
        while (fastNode != slowNode)
        {
            fastNode = fastNode.next.next;
            slowNode = slowNode.next;
    ​
            if (fastNode == null || fastNode.next == null)
            {
                return null;
            }
        }
    ​
        fastNode = head;
        while (fastNode != slowNode)
        {
            fastNode = fastNode.next;
            slowNode = slowNode.next;
        }
    ​
        return fastNode;
    }

    现在时间不多,后续二刷应该会有新的理解。

代码实现

 public ListNode DetectCycle(ListNode head)
 {
     ListNode fastNode = head, slowNode = head;
​
     while (fastNode!=null && fastNode.next!=null)
     {
         fastNode = fastNode.next.next;
         slowNode = slowNode.next;
​
         if (fastNode==slowNode)
         {
             fastNode = head;
             while(fastNode!=slowNode)
             {
                 fastNode = fastNode.next;
                 slowNode = slowNode.next;
             }
             return fastNode;
         }
     }
     return null;
 }

后记

这四道题昨天(5.7)就开始写了,但能力有限吧一天下来只写完了3道题,记录也只整理回顾了前2道题的。

现在开始难度有点上来了,愈发发现自己的算法能力拉下太多了。

此后会将算法的练习作为每天最优先的任务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1678117.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[数据结构]红黑树的原理及其实现

文章目录 红黑树的特性红黑树的时间复杂度推导&#xff1a;结论红黑树与AVL树比较 红黑树的插入红黑树的节点定义调整策略思考情况2&#xff1a;思考情况3&#xff1a; 代码实现myBTRee.htest.cpp 红黑树的特性 红黑树最常用的平衡二叉搜索树。跟AVL树不同的是&#xff0c;红黑…

OpenAI 推出革命性新模型 GPT-4o:全能AI的新纪元

GPT-4o 模型的推出预示着人工智能领域的又一次飞跃&#xff0c;它将如何改变我们的世界&#xff1f; 在人工智能的快速发展浪潮中&#xff0c;OpenAI 再次站在了技术革新的前沿。2024年5月14日&#xff0c;OpenAI 宣布了其最新旗舰模型 GPT-4o&#xff0c;这不仅是一个简单的版…

GitHub操作

远程库-GitHub GitHub网址 GitHub是全球最大的远程库 1. 创建远程库 2. 远程仓库操作 2.1 创建远程仓库别名 git remote -v 查看当前所有远程库地址别名 git remote add 别名 远程地址 设置远程库地址别名 案例操作 起一个别名会出现两个别名&#xff0c;是因为既可以拉取…

艺人百度百科怎么创建

创建艺人百度百科是一个相对复杂的过程&#xff0c;需要遵循一定的步骤和规则。以下是百科优化网yajje整理的艺人百度百科创建指南&#xff1a; 了解百度百科的创建流程 在创建艺人百度百科页面之前&#xff0c;首先需要了解百度百科的创建流程。可以通过访问百度百科的官方网…

uniapp如何打包预约上门按摩APP

uniapp如何打包预约上门按摩APP&#xff1f; 开发工具&#xff1a;HBuilderX 一、创建移动应用 1、 点击此处微信开放平台 2、点击【管理中心 - 移动应用 - 创建移动应用】填写资料后等待审核 app运行流程图 签名如何获取&#xff1a; 1&#xff09;先把打包好的app安装在手…

防爆安检系统市场规模保持增长态势 行业将向智能化方向发展

防爆安检系统市场规模保持增长态势 行业将向智能化方向发展 防爆安检系统&#xff0c;是指为了防止爆炸物品及其他危险物品进入特定区域而设置的一套完整的设备系统&#xff0c;细分产品包括金属探测器、生物安全检测设备、爆炸物探测器等。防爆安检系统能够有效检测并识别出潜…

单文件组件,为什么要使用 SFC

介绍 Vue 的单文件组件 (即 *.vue 文件&#xff0c;英文 Single-File Component&#xff0c;简称 SFC) 是一种特殊的文件格式&#xff0c;使我们能够将一个 Vue 组件的模板、逻辑与样式封装在单个文件中。下面是一个单文件组件的示例&#xff1a; <script setup> impor…

【Qt】之【CMake】Error : The source.. does not match the soused

QT中cmak编译出现CMake Error: The source… does not match the soused 分析 前提是该项目是从另一个路径的项目复制过来的&#xff0c;编写代码时发现无论怎样修改代码&#xff0c;运行后都没有任何变化&#xff0c;以为是qtbug&#xff0c;重构重启都没用&#xff0c;最后…

Spring注解驱动开发

1、Spring注解驱动开发图解

旅游集市数仓建设

旅游集市数仓建设 小白如何从0到1成为大数据工程师 目录 旅游集市数仓建设 1.上传数据 2.可能用到的UDF函数 3.创建所需数据库及表 1&#xff09;ODS层 ①ods_oidd ②ods_wcdr ③ods_ddr ④ods_dpi 2&#xff09;DWD层 ①dwd_res_regn_mergelocation_msk_d ②dwm_s…

2024年5月面试知识点梳理

2024年5月面试知识点梳理 资料来源Java基础泛型注解异常反射SPI机制Java集合CollectionMap 并发基础线程并发关键字并发集合Lock核心类并发集合核心类原子类核心类线程池核心类ScheduledThreadPoolExecutorForkJoinPoolFokJoinTask JUC原子类: CAS, Unsafe和原子类详解JUC 工具…

【Linux】linux | 配置系统日志 | 安全日志 | 操作日志 | 登录日志

一、诉求 1、linux服务器开启日志功能&#xff0c;并记录10个月的登录 二、操作 1、进入目录 cd /etc 2、编辑配置 vi logrotate.conf 3、复制配置 /var/log/wtmp {monthlycreate 0664 root utmpminsize 1Mrotate 10 }/var/log/btmp {missingokmonthlycreate 0600 root …

多客陪玩系统,陪玩系统源码,线下搭子,爆改家政整理师等功能,陪玩预约系统 定制化陪玩系统,陪玩软件APP小程序H5游戏陪玩成品软件源码

简述 陪玩系统源码是指一款游戏陪玩平台的程序代码。陪玩系统通常是一个在线平台&#xff0c;可以让用户通过该平台找到愿意为他们提供游戏陪玩服务的人员&#xff0c;从而帮助他们在游戏中取得更好的成绩。这种系统通常包括客户端和服务器端两个部分&#xff0c;客户端用于用…

【强训笔记】day23

NO.1 思路&#xff1a;直接计算结果&#xff0c;先计算怪物可以抗几次攻击&#xff0c;再计算勇士受到的伤害&#xff0c;如果勇士的攻击力大于等于怪物的血量&#xff0c;那么就可以击杀无数只&#xff0c;如果勇士的血量正好是受到攻击的整数倍&#xff0c;那么击杀的怪物数…

服务攻防——应用协议软件,设备平台

向日葵利用 vnc利用5900端口 当为none就可以直接连接&#xff0c;而其他几种密码也能破解 可以使用hydna来尝试爆破 teamviewer(cve2020-13699) 让对方点击这个网站&#xff0c;就会 触发 zabbix 端口10051 cve2020 手工 点击这个 找到cookie 然后不需要密码就能进…

手心经常出汗、多汗是怎么回事?

点击文末领取揿针的视频教程跟直播讲解 手心爱出汗是一种怎样的体验&#xff1f; 手握着鼠标&#xff0c;一会儿就变得湿漉漉&#xff0c;小心翼翼拿着手机&#xff0c;防止它从满是汗的手掌滑出去……其实手心总出汗可能是一种病。 很多人都有手掌心出汗的症状。如果年轻健康…

【leetcode面试经典150题】-26. 删除有序数组中的重复项

26. 删除有序数组中的重复项 1 题目介绍1 个人解题思路1.1 解题代码1.2 思路解析 2、分析官方题解2.1 快慢双指针 1 题目介绍 给你一个 非严格递增排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新…

佛山信息学真题 桂城-2021-五年级1.2

一、两位数&#xff08;GC4091&#xff09; GC4091 GC.2021.五年级.01.两位数http://43.139.152.26/d/DH_Trial/p/GC4091 题目描述 小明正在思考一个数学问题&#xff1a;有一个两位数&#xff0c;它的十位数大于等于个位数。现已知它的十位数和个位数之和为a&#xff0c;十位…

在pycharm添加pyqt5外部工具插件

一&#xff1a;查看环境所在位置以及安装pyqt5库 1、打开anaconda&#xff0c;输入以下命令&#xff0c;查看环境名&#xff0c;以及环境所在位置。 conda info --envs 从图中得知以下信息&#xff0c;下面根据自己实际情况&#xff0c;记住环境名和路径 ①环境名是&#xf…

Google IO 2024有哪些看点呢?

有了 24 小时前 OpenAI 用 GPT-4o 带来的炸场之后&#xff0c;今年的 Google I/O 还未开始&#xff0c;似乎就被架在了一个相当尴尬的地位&#xff0c;即使每个人都知道 Google 将发布足够多的新 AI 内容&#xff0c;但有了 GPT-4o 的珠玉在前&#xff0c;即使是 Google 也不得…