首页 > 编程语言 >【基础算法】单链表的OJ练习(2) # 链表的中间结点 # 链表中倒数第k个结点 #

【基础算法】单链表的OJ练习(2) # 链表的中间结点 # 链表中倒数第k个结点 #

时间:2023-06-13 23:32:58浏览次数:55  
标签:count 结点 OJ fast next 链表 节点 指针

前言

  • 对于单链表的OJ练习,<font color=blue size=4>需要深刻理解做题的思路</font>,这样我们才能够在任何场景都能够熟练的解答有关链表的问题。

  • 关于OJ练习(1):==->== 传送门 ==<-==,其题目较为简单,思路也好理解,本章与(1)差不多,难度不大,<font color=orange size=4>核心点就在于理解解题思路。</font>


链表的中间结点

题目链接:==->== 传送门 ==<-==。

  • 该题目描述为:<font color=red size=4>给你单链表的头结点 head ,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。</font>

1.如果节点数为奇数,这个中间节点就显而易见了。(3) 在这里插入图片描述

2.如果节点数为偶数,这里认为中间两个节点的第二个节点为中间节点。(4) 在这里插入图片描述

<font color=red size=4>思路一</font>:

  • 我们可以先遍历一遍链表,统计一下链表节点的个数。

  • 然后将这个个数除以二加一(count / 2 + 1)便是中间这个节点的位置。

  • 当然,我们在循环寻找这个中间节点的时候,是从头节点开始的,因此循环只需要循环((count / 2 + 1) - 1)即可。

<font color=blue size=4>代码实现:</font>

struct ListNode* middleNode(struct ListNode* head){
    struct ListNode* cur = head;
    int count = 0;

    while (cur)
    {
        count ++ ;
        cur = cur->next;
    }

    count = count / 2 + 1;

    while (-- count) // 循环count - 1次
    {
        head = head->next;
    }

    return head;
}

<font color=red size=4>思路二</font>:

  • 该做法为快慢指针。

  • 啥为快慢指针呢?在本题有关当中,我们定义两个指针指向链表的头节点,并且共同遍历链表,不同的是,一个指针每一次走两步,另一个指针每次走一步,这就是快慢指针。

  • 每当快指针满足循环结束条件,慢指针都是指向链表的中间节点的。因为快指针走两步,慢指针走一步,整个移动的位移差相差一倍,所以每当快指针满足结束条件的时候,慢指针走的步数都是快指针走的步数的一半, 因此慢指针指向的那个节点就是整个链表的中间节点。

  • 快指针结束的条件有两种情况,一种是快指针刚好指向空结束,一种是快指针指向尾节点结束,也就是快指针的nextNULL

1.当快指针刚好指向NULL结束,此时链表的节点个数为偶数:

在这里插入图片描述

2.当快指针指向尾节点结束,也就是快指针的nextNULL,此时链表的节点个数为奇数:

在这里插入图片描述

<font color=blue size=4>代码实现:</font>

struct ListNode* middleNode(struct ListNode* head){
    struct ListNode* fast = head, * slow = head;

    while (fast && fast->next)
    {
        fast = fast->next->next;
        slow = slow->next;
    }

    return slow;
}

<font color=red size=4>注意:</font> while循环的判断条件,fast一定要在前面,这是因为:判断是从左到右判断的,如果fast->next在前,而此时链表的结点的个数为偶数,那么fast就会直接到达NULL,这时候对空指针解引用操作就出问题了。


链表中倒数第k个结点

题目链接:==->== 传送门 ==<-==。

  • 该题目描述为:<font color=red size=4>输入一个链表,输出该链表中倒数第k个结点。。</font>

在这里插入图片描述

<font color=red size=4>思路一</font>:

  • 既然是倒数第k个,那我们就看看是正数的第几个。

  • 先遍历一遍单链表,统计一下链表的结点个数(count),通过数学知识,可得倒数的第k个结点就是正数的第count - k + 1个节点,这时只要在遍历一次链表,找到第count - k + 1个节点返回即可。

  • 当然,这里嘚注意k是不是大于链表节点的个数的情况。

<font color=blue size=4>代码实现:</font>

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    struct ListNode* cur = pListHead;

    int count = 0;
    // 统计链表节点的个数
    while (cur)
    {
        count ++ ;
        cur = cur->next;
    }

    // 如果k大于链表的节点个数,直接返回NULL
    if (k > count) return NULL;
    
    int tmp = count - k;
	
	// 由于从头个节点开始算,因此只需要循环count - k次就可以找到倒数第k个节点
    while (tmp -- )
    {
        pListHead = pListHead->next;
    }

    return pListHead;
}

<font color=red size=4>思路二</font>:

  • 同样是快慢指针,这里的快慢指针解法是:快指针先向后走k步或者先向后走k - 1步,然后快指针与慢指针同时向后走,当快指针满足循环结束条件停止,此时慢指针指向的节点就是倒数第k个节点。

1.如果快指针先向后走k步,此时快指针与慢指针之间相差k步,因此,当快指针到达NULL时,此时慢指针刚好指向倒数第k个节点。(倒数第k个节点与NULL相差k步)(循环结束条件:fast == NULL)

在这里插入图片描述

2.如果快指针先向后走k - 1步,此时快指针与慢指针之间相差k - 1步,然后快指针与慢指针同时向后走,当快指针满足循环结束条件停止,此时慢指针指向的节点就是倒数第k个节点。(倒数第k个节点与尾节点相差k - 1步)(循环结束条件:fast->next == NULL

在这里插入图片描述

<font color=blue size=4>代码实现:(这里只实现fast先走k步的情况,fast先走k - 1的情况大同小异)</font>

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    struct ListNode* slow = pListHead, * fast = pListHead;
    // fast先走k步
    while (k -- )
    {
        if (!fast) return NULL; // 如果k还没为0但fast已经指向空了,说明k大于链表的结点的个数,此时直接返回NULL
        fast = fast->next;
    }
	
	// 当fast为NULL时结束循环
    while (fast)
    {
        fast = fast->next;
        slow = slow->next;
    }

    return slow;
}

写在最后

<font color=red size=4>对于单链表的题目练习,最重要的是思路,我们在数据结构阶段要养成画图的习惯,因为它能帮助我们更好的理解。后续还会有单链表相关的题目练习。</font>

<font color=blue size=4>感谢阅读本小白的博客,错误的地方请严厉指出噢!</font>

标签:count,结点,OJ,fast,next,链表,节点,指针
From: https://blog.51cto.com/u_16019252/6474510

相关文章

  • Loj #6041. 「雅礼集训 2017 Day7」事情的相似度
    做到这题,发现自己对\(SAM\)的一些性质还不知道,特此记录。题目要求01字符串区间内前缀的最长公共后缀由SAMparenttree性质可知,2个前缀的最长公共后缀就是它们在parenttree上lca的len值如何去感性理解我们知道,在parenttree上每个节点都代表了一个endpos等价类,由后缀链接将他......
  • POJ 3131 - Cubic Eight-Puzzle
    很明显可以看出是一道搜索题。首先考虑\(bfs\),第一种思路是每次从给定的初始状态都进行一次\(bfs\),直到\(30\)停止。然后我们发现,初始状态根据一开始空格的位置不同,一共只有\(9\)种。而一个状态可以用空格的位置、所有位置上方的颜色、所有位置左方的颜色唯一确定,一共\(6^......
  • mmhmm重塑视频会议、2020新款emoji可爱来袭、微软将推云游戏服务xCloud等| Decode the
    Social MediaSucks.DecodetheWeek≠音视频技术周刊 NewsBriefing1. Evernote前CEO推出虚拟摄影棚应用mmhmm重塑视频会议PhilLibin带领Evernote创造辉煌后,再次回到消费与企业应用的交界,推出虚拟相机云服务mmhmm(中文发音是“嗯哼”)。mmhmm可在Zoom、GoogleMeet、YouTube以......
  • Open Project 系列3 --- 备份与还原
    一、概要1.承上启下OpenProject系列2.简介OpenProject提供了两种备份方式,一种是Admin用户通过页面备份,另一种是通过命令备份。本文选择通过命令备份的方式。3.备份内容a.存储在Postgres中的数据;b.配置文件;c.上传的文件(附件);d.Git/SVN仓库(如果有的话)。二、......
  • 【基础算法】单链表的OJ练习(1) # 反转链表 # 合并两个有序链表 #
    前言上一章讲解了单链表==->==传送门==<-==,后面几章就对单链表进行一些简单的题目练习,目的是为了更好的理解单链表的实现以及加深对某些函数接口的熟练度。本章带来了两个题目。一是<fontcolor=red>反转链表</font>,二是<fontcolor=red>合并两个有序链表</font>,整体难......
  • dojo\dart脚本编程语言
    Dojo是一个用于构建高效、可扩展的Web应用程序的开源JavaScript框架。它提供了一系列功能丰富的模块和组件,包括DOM操作、事件处理、异步编程、动画效果等。Dojo还具有强大的用户界面(UI)工具包Dijit,可以帮助开发人员轻松实现各种复杂的界面交互。Dojo的主要特点包括:1.模块化:Dojo采......
  • 「UOJ700」可爱多的字符串
    题目有一次机灵鬼和学长可爱多打比赛,可爱多不会做一道字符串题,机灵鬼做了很久终于做出来了,这是机灵鬼第一次做出可爱多不会的题。可爱多觉得很丢人,于是准备研究字符串。可爱多精通\(\mathrm{kmp}\)算法。\(\mathrm{kmp}\)算法的输入是一个字符串\(S\),该算法的核心是对每个......
  • Open Project 系列2 --- 集成LDAP
    一、概要1.承上启下OpenProject系列二、配置1.配置页面OpenProject可以通过页面来配置LDAP。(1)使用Admin账户登录后点击右上角头像,进入"Administration->Authentication->LDAPAuthentication"页面:(2)点击右上角的"Authenticationmode":三、参考1.官方ht......
  • 深入理解 DAO,DTO,DO,VO,AO,BO,POJO,PO,Entity,Model,View 各个模型对象的概念
    参考文档:https://blog.csdn.net/SR02020/article/details/105821816 深入理解DAO,DTO,DO,VO,AO,BO,POJO,PO,Entity,Model,View的概念DAO(DataAccessObject)数据访问对象DTO(DataTransferObject)数据传输对象DO(DomainObject)领域对象VO(ViewObject)视图模型AO(ApplicationObject)应用对象......
  • poj-2823 Sliding Window(单调队列)
    原题链接SlidingWindowTimeLimit: 12000MS MemoryLimit: 65536KTotalSubmissions: 54929 Accepted: 15814CaseTimeLimit: 5000MSDescriptionAnarrayofsize n ≤106 isgiventoyou.Thereisaslidingwindowofsize k whichismoving......