
C语言习题题解
文章平均质量分 55
本专栏将不定时发布相关编程习题的题解,目的在于复习和提供给读者更多的思路
对编程一片赤诚的小吴
永远保持一颗学习的心
展开
-
C语言每日一题(64)快乐数
这道题数据的取值范围是2的31次方-1,转换一下等于2147483647,我们取到数字个数的最大值,即9999999999,可以推导出,这个数通过题目的方法取到的数,一定是最大的(因为原数比范围还大,同时也是各位上的最大值),即81*10=810,所以,测试样例的变化范围就在【1,810】之间,不会有大于它的数存在。没什么好说的,很简单;设需要检测的数为x,假设最坏情况,它变化了810次都没有重复的数存在,说明它已经将1——810的数已经遍历完一遍,当进行第811次时,必定有重复值出现。原创 2024-03-18 19:19:16 · 1229 阅读 · 0 评论 -
C语言每日一题(63)复写零
1.当arr【cur】等于0时,将dest指针移动到cur位置,然后cur加一,从cur位置开始到整个数组结束,元素整体向右移动,最后在cur位置加个0即可。按照题目要求直接实现,定义两个指针cur和dest,两个指针从零开始,cur用来扫描整个数组。调用函数后,输入的数组将被修改为:[1,0,0,2,3,0,0,4],请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。2.当arr【cur】不等于0时,cur往下走,dest不动。调用函数后,输入的数组将被修改为:[1,2,3]原创 2024-03-12 20:13:18 · 516 阅读 · 0 评论 -
C语言每日一题(62)移动零
定义两个指针cur和prev,从最左边开始,如果nums【cur】==0的话,cur往下走,此时定义一个计数器记录0的个数,当nums【cur】不为0时,就将该值赋给prev的位置,之后prev往下走,cur也往下走,直到cur越界,此时prev指向的位置就是需要赋值0的位置。同样定义两个指针prev和cur,当cur的值等于0时,cur就往下走,直到cur不等于0时,此时它与prev的间隔数就是0的个数,将cur的值于prev的值交换,然后prev往下走,直到cur越界完成。空间复杂度:O(1)原创 2024-03-05 23:32:50 · 348 阅读 · 0 评论 -
C语言每日一题(61)盛最多水的容器
关于无论怎样移动右指针,左指针都不会成为容器的边界(左指针最小)了这句话,我有点稀里糊涂,我的理解可能就在于左指针的值对于容器容量不起决定性作用了,因为无论右指针大还是小,移动后的容量肯定比之前的少(题解有证明),万一一开始的容量不是最大该怎么办?定义左右两个指针分别向数组中间走,可以看出,容器的容量就是两个指针指向的值中最小的那个值乘以两个指针之间的距离,可以用木桶效应来解释,即桶的容量取决于最短的那块木板。第一次结果出来后,值较小的指针往中间走,这期间更新最大值,直到俩指针相遇。原创 2024-02-23 21:36:40 · 1931 阅读 · 4 评论 -
C语言每日一题(60)对链表进行插入排序
链表的插入操作:将lastsorted指针的next指向cur的next,cur的next指向prev的next,也就是lastsorted,随后prev的next指向cur即可。1.lastsorted:指向待插入链表的最后一个位置的指针(插入排序将插入位置前面的部分看成是已经有序的),最开始指向head。小于的话,prev指针从dummy开始遍历,找到需要插入的结点的前一个结点进行插入操作。3.prev:指向插入位置的前一个结点,插入时使用,最开始指向dummy(哨兵位)对链表进行排序,并返回。原创 2024-02-21 21:48:31 · 631 阅读 · 0 评论 -
C语言每日一题(59)左叶子之和
最后去往右子树找,右子树的递归条件和左子树不一样,因为右子树也会存在有左叶子结点的情况,所以如果右子树是一个叶子结点的话就没必要递归了,但如果不是的话,就得往右子树里找。其次去往左子树找,如果左子树存在且不为叶子结点的话,继续往它的左子树找,直到找到叶子结点为止,如果是叶子结点,直接返回它的值累加到一个变量里。题目要求找左叶子的和,那么前提是它一定是一个叶子结点,其次才判断它是否是左叶子。在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24。,返回所有左叶子之和。如果根结点为空,返回0;原创 2024-02-18 19:24:03 · 519 阅读 · 0 评论 -
C语言每日一题(58) 叶子相似的树
递归细节:如果左右孩子都为空,说明递归到叶子结点了,就将这个结点的值放入数组,如果不是,如果左孩子存在,就递归到左孩子,如果右孩子存在,就递归到右孩子。请考虑一棵二叉树上所有的叶子,这些叶子的值按从左到右的顺序排列形成一个。如果有两棵二叉树的叶值序列是相同,那么我们就认为它们是。举个例子,如上图所示,给定一棵叶值序列为。如果给定的两个根结点分别为。的树是叶相似的,则返回。原创 2024-02-15 08:30:00 · 433 阅读 · 0 评论 -
C语言每日一题(57)二叉树的最小深度
当左孩子和右孩子同时为空时,返回1,说明碰到了叶子结点,如果其中一个结点不为空或者同时存在,先从左孩子开始递归,左孩子完到右孩子,直到找到叶子结点返回。首先理解,最小深度是从根节点到最近叶子节点的最短路径上的节点数量。接着实现大小的问题,我们分别将左右孩子递归的结果用一个变量保存,再找出最小的就可以了。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。给定一个二叉树,找出其最小深度。叶子节点是指没有子节点的节点。原创 2024-02-14 08:30:00 · 343 阅读 · 0 评论 -
C语言每日一题(56)平衡二叉树
找出左右子树的高度,如果高度差出现大于一的情况就返回false,从根节点开始,先从左子树找,再去右子树找。这里为了方便判断左右子树高度大小,利用了假设法,先假设左子树高度最高,后面再判断一下,如果不对就换一下。给定一个二叉树,判断它是否是高度平衡的二叉树。的左右两个子树的高度差的绝对值不超过 1。原创 2024-02-13 18:54:23 · 841 阅读 · 0 评论 -
C语言每日一题(55)另一颗树的子树
和相同二叉树是一个道理,但有一个情况:当根节点相同时,我们还得去比较所匹配子树的左右结点,而且会存在根节点不相同的情况,就需要去到左右结点去找,直到找到相同的。具有相同结构和节点值的子树。的某个节点和这个节点的所有后代节点。也可以看做它自身的一棵子树。原创 2024-02-12 08:30:00 · 287 阅读 · 0 评论 -
C语言每日一题(54)对称二叉树
和相同二叉树是一个道理,但判断相同的不是两颗子树对应的左右结点,而是将两颗子树的左右结点交错进行判断,即左孩子与右孩子判断,右孩子和左孩子判断。给你一个二叉树的根节点。, 检查它是否轴对称。原创 2024-02-11 08:30:00 · 237 阅读 · 0 评论 -
C语言每日一题(53)翻转二叉树
从叶子节点开始翻转,翻转时,保留左右孩子结点,进行交换。,翻转这棵二叉树,并返回其根节点。给你一棵二叉树的根节点。原创 2024-02-10 08:30:00 · 386 阅读 · 0 评论 -
C语言每日一题(52)单值二叉树
和相同二叉树是一个道理,也是判断两个结点情况,但这次是要从根结点开始判断,一旦值不相等就返回false。如果二叉树每个节点都具有相同的值,那么该二叉树就是。只有给定的树是单值二叉树时,才返回。原创 2024-02-09 08:30:00 · 325 阅读 · 0 评论 -
C语言每日一题(51)相同的树
还是基于递归的思想,但我们需要考虑一些特殊情况,递归过程中,如果碰到两个结点为空的情况,说明此时已经递归到两棵树的叶子结点了,而中途没有进行返回,说明两颗树相同。当两棵树有一个结点不相等的话,此时就要返回false了,除此之外,如果存在其中一个结点为空而另外一个结点不为空,也是要返回false的。如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。,编写一个函数来检验这两棵树是否相同。给你两棵二叉树的根节点。原创 2024-02-08 08:30:00 · 312 阅读 · 0 评论 -
C语言每日一题(50)二叉树的最大深度
每一次递归,都要判断该节点的左右子树的最大值,直到递归到最下面的叶子节点,为空返回0,同时每一次返回时,记得加1,这是当前结点本身。基于递归的思想,从根结点开始,找出左右子树的最大值并返回,同时加上1(根节点本身)就是二叉树的最大深度。是指从根节点到最远叶子节点的最长路径上的节点数。原创 2024-02-07 20:58:39 · 443 阅读 · 0 评论 -
C语言每日一题(49)二叉树的三种基本遍历方法
链式二叉树、递归。原创 2024-01-30 21:59:09 · 230 阅读 · 0 评论 -
C语言每日一题(48)回文链表
请你判断该链表是否为回文链表。给你一个单链表的头节点。原创 2024-01-25 23:03:59 · 668 阅读 · 0 评论 -
C语言每日一题(47)两数相加II
和两数相加比起来,这道题的难点在于它不是逆序的而是正序的,这意味着你不能直接在两个链表上进行操作,但可以逆转链表再进行操作,但这样工作量就会很大了,还容易出错。链表来代表两个非负整数。数字最高位位于链表开始位置。将这两数相加会返回一个新的链表。这里需要用到三个栈,一个存放链表1,一个放链表2,最后一个用来放和,和之前一样,进位的问题也得单独考虑进去。我做题做了很久,发现一般跟逆序有关系的基本上都可以用栈进行解决,毫无疑问,这里也可以。你可以假设除了数字 0 之外,这两个数字都不会以零开头。原创 2024-01-24 19:22:37 · 507 阅读 · 1 评论 -
C语言每日一题(46)整数转罗马数字
拷贝细节:最开始的开辟的字符串长度为0,每次需要拷贝时,我们将字符串的首地址(数组名)加上它的长度,避免每次拷贝时会覆盖原来的字符串。我们寻找不超过 num 的最大符号值,将 num 减去该符号值,然后继续寻找不超过 num 的最大符号值,将该符号拼接在上一个找到的符号之后,循环直至 num为 0。我们将对应的字符和数字存入两个对应的数组value和symbols,遍历value数组,找到不超过num的最大值的下标,将下标对应的symbols里的字符拷贝到我们需要返回的开辟的字符串里即可。原创 2023-12-05 19:44:58 · 1276 阅读 · 2 评论 -
C语言每日一题(45)删除排序链表中的重复元素
有了44题的基础,这道题简直易如反掌。基于44题的思路,我们这次直接从头结点和它的下一个结点开始扫描,连哨兵位也不用定义。这题不同的点在于重复的元素至少要保留一个,所以扫描时如果下一个结点的值等于当前结点的值,我们就从下一个结点开始删,直到值不等时,继续遍历。删除所有重复的元素,使每个元素只出现一次。给定一个已排序的链表的头。原创 2023-12-04 18:43:20 · 637 阅读 · 1 评论 -
C语言每日一题(44)删除排序链表中的重复元素 II
一次遍历即可,题目所给的链表已经升序排列好了,那如果有重复元素的话他一定是放在一起的,也就是连续的,所以我们从头结点和它的下一个开始,如果相等的话,我们就将后面的链表向前移动进行覆盖实现删除,直到两个不等时继续遍历到链表结束。为了方便扫描所有结点的值,我们定义一个哨兵位,从哨兵位开始遍历,返回时指向哨兵位的下一位就是头结点了。删除原始链表中所有重复数字的节点,只留下不同的数字。给定一个已排序的链表的头。原创 2023-12-03 11:24:41 · 578 阅读 · 3 评论 -
C语言每日一题(43)旋转链表
后面我发现了一种思路,也是截断法,但不同的在于它是一次性截完,我们之前写过一题,找出链表的倒数第N个结点,比如说n=2,当我们找到了倒数第二个结点时,我们发现,该节点后面的所有结点不就是我们所需要旋转的结点吗,我们就没必要一个个截断,找到所有需要旋转的点一次性截断就行了。最开始的时候我是尝试过截断法的,就是每旋转一次,就将后面的结点指向头结点并把前面的结点的指针截断置空,但后面调试发现,这只适用于旋转一次,因为旋转后,新的尾结点的前驱结点找不到了,就算实现了,时间复杂度O(n2)也挺高的。原创 2023-12-01 20:04:31 · 632 阅读 · 2 评论 -
C语言每日一题(42)删除链表的倒数第N个结点
我们通过快慢指针法遍历链表,得到slow指向的结点就是需要删除的结点,但此时还得需要获得它的前驱结点,这时就得定义第三个指针在遍历的时候指向它的前驱结点,且又得考虑链表为空的情况(在方法2不带哨兵位会进行解释)但如果有了哨兵位,我们可以让快指针从头结点开始,二慢指针从哨兵位开始,遍历结束后,slow指针的下一个就是要删除的结点,相当于不找删除结点,而是找删除结点的前驱结点,直接指向下一个结点的下一个完成删除。当我们需要删除的结点是头结点,就需要将head指针移动到下一个当作新的头结点再将原来的结点释放。原创 2023-11-30 17:27:12 · 961 阅读 · 1 评论 -
C语言每日一题(41)循环队列
检查循环队列是否为空:在初始化时,我们将front和back都设为0为最开始的位置,每次放入数据,back都会往后移动,而出队的话front就会往后移,当front移动到back位置时,队就空了,即当front=back时,队列就为空了。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。定义多一个空间,当往里面放数据时,back不断向后移动,如图队列有效长度为5,队满的情况下,back是不存放数据的,此时发现只要back下一个为front,队就满了。原创 2023-11-29 08:55:25 · 1420 阅读 · 1 评论 -
C语言每日一题(40)栈实现队列
从队列的开头移除并返回元素:这里就有讲究了,出栈是将最后进入的元素返回,但出队却是将最先进入的元素返回,但又不能取到栈底元素,所以我们需要再定义一个栈来进行出队用,定义为popst,出队的时候,只需要将pushst里的元素全部出栈,进栈到popst中,再返回popst栈顶元素自然就是需要出队的元素了。将元素 x 推到队列的末尾:关于进队,没有具体的返回值,对于系统如何进行存储也没有过多要求,我们就定义一个pushst(用来进队元素的栈),将元素直接push即可。针对队列的四个功能,我们逐一讲解并进行实现。原创 2023-11-27 15:44:22 · 2475 阅读 · 1 评论 -
C语言每日一题(39)寻找两个正序数组的中位数
根据元素个数决定,如果个数为奇数,中间那个就是中位数,如果为偶数,则中间的和前一个元素的平均数就是中位数。合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5。最基本的思路,将两个数组重新排序到一个新的数组里,之后再求这个数组的中位数。合并数组 = [1,2,3] ,中位数 2。请你找出并返回这两个正序数组的。的正序(从小到大)数组。算法的时间复杂度应该为。原创 2023-11-26 11:02:51 · 792 阅读 · 0 评论 -
C语言每日一题(38)无重复字符的最长字串
随后开始遍历整个字符串,这里需要两层循环,利用每一个字符的ascii编码当作数组的下标,如果下标对应的值为零,我们设置为1,并进入下面if语句的运行,如果下一个字符和它相等,就不会进入接下来的判断,这是判断不出现重复字符的方法。关于求最长的字串长度,我们利用两个下标,从第一个字符开始,如果接下来的字符对应的下标的数组为0就进入if语句,此时遍历的两个下标的差值在加上原来的第一个字符(也算不重复的字串)便是不出现重复字符字串的长度,同时定义一个max值保留每一次的最大值即可。,请你找出其中不含有重复字符的。原创 2023-11-25 20:43:48 · 749 阅读 · 0 评论 -
C语言每日一题(37)两数相加
换一种思路,我们直接在现成的两个链表上操作,可以看到,相加后逆过来的值刚好就是对应的两个结点的相加,那我们可以直接遍历两个链表,将对应的值相加,并存放到新的结点里。最基本的思路,就是将俩链表转正过来,相加后再进行逆序,实现是可以实现,但时间复杂度太高了,此外这里相加还涉及到进位的问题,这样做会很麻烦。1.这里会涉及到进位的问题,我们可以将相加后的值/10得到进位值(大于10的进位值为1,小于10的进位值为0)每次相加时加上进位值即可。2.还会存在链表结点数不等的情况,我们将不存在的结点数的值视为0即可。原创 2023-11-24 16:41:58 · 885 阅读 · 1 评论 -
C语言每日一题(36)队列实现栈功能
这里先描述出栈的实现,假设一个队列里已经放好了值,为1,2,3,4,按照队列出队的话,先取到1,但如果出栈的话,就需要取到4,这里另外一个队列就派上用场了,我们可以将队尾前的所有元素出队,并进入到另一个队列里,最后剩下的就是需要出栈的元素,此时我们在去原队列的队头元素即可。接下来到入栈的实现,关键在于应该入哪个队,如果两队为空,随便一个,但接下来的话如果要方便上述出栈的实现,我们就需要入队到不为空的队列。紧接着是返回栈顶元素,我们已经知道,队尾就是我们出栈的元素,所以这里直接返回队列的队尾元素即可。原创 2023-11-23 21:10:28 · 735 阅读 · 1 评论 -
C语言每日一题(35)有效的括号
这里除了括号类型的匹配问题,同时还有数量问题,会存在左括号多于右括号或者反过来的情况,这里如果数量不匹配的话也返回false。如果这里再用所谓的遍历字符串寻找进行匹配的话,时间复杂度高且不说,还麻烦,但如果我们学习栈了以后,这道题会变得异常轻松。我们将所有的左括号入栈,在字符串里找右括号,同时出栈左括号进行匹配,如果匹配成功就返回true,否则返回false。判断数量的问题,再寻找右括号时,先判断栈是否为空,这是判断右括号多余左括号的情况,力扣环境下是不提供栈的,这里我们需要自己定义。原创 2023-11-22 22:26:16 · 639 阅读 · 1 评论 -
C语言每日一题(34)链表的回文结构
对于存在的结点个数为奇数或偶数的情况,当找到中间结点并进行逆置时,偶数情况下则是正常情况,奇数情况下,中间结点逆置后,它的前驱结点的next值依然指向逆置后的中间结点,不影响遍历。找到链表的中间结点,将中间结点后的链表进行逆置,一个从头开始遍历到中间结点,一个从中间结点遍历到尾结点进行匹配,如果存在值不相等的就不是回文链表。对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。,请返回一个bool值,代表其是否为回文结构。给定一个链表的头指针。原创 2023-11-20 09:00:00 · 117 阅读 · 0 评论 -
C语言每日一题(33)随机链表的复制
将要复制的结点插入到每一个源节点的后面,记为copy,题目要求copy的random不能指回源节点,只能值向复制的结点,会发现,如果要取到对应的复制结点,例如原节点13的random指向7,那复制结点13也要指向复制的7,怎么取到呢,就是原结点13的random的next,是不是很巧妙?其实就是一个关于链表的拷贝,像一般的单链表只需要遍历一遍复制即可,但这个链表多了一个随机指针random,它可以指向链表中的任意一个结点,包括它自己,同时也可以指向空。节点组成,其中每个新节点的值都设为其对应的原节点的值。原创 2023-11-19 11:27:21 · 220 阅读 · 5 评论 -
C语言每日一题(32)环形链表
指针再次到达,则链表中存在环。为了表示给定链表中的环,评测系统内部使用整数。快慢指针法,快指针走两步,慢指针走一步,如果两者相同,则证明该链表带环。来表示链表尾连接到链表中的位置(索引从 0 开始)。如果链表中有某个节点,可以通过连续跟踪。链表中有一个环,其尾部连接到第二个节点。仅仅是为了标识链表的实际情况。,判断链表中是否有环。给你一个链表的头节点。原创 2023-11-18 09:00:00 · 181 阅读 · 0 评论 -
C语言每日一题(31)相交链表
到第二个问题,找交点,如果俩链表同时从头遍历,再找它们相同的结点的话,那么当俩链表长度不同,指针就会错位,这是不靠谱的做法,正确的做法是,将它们遍历的起点进行统一后再进行遍历,直到碰到相同的结点,就是它们的交点。首先找出较长链表,将俩链表长度的差当作步数,让长链表的指针先走完这些步数,这样两个链表的指针就统一了,之后两个指针再一起遍历,直到碰到相同结点停止,返回任意一个指针即是对应的交点。,请你找出并返回两个单链表相交的起始节点。注意比较的是该节点而非该节点的值,因为链表是乱序且无规律的。原创 2023-11-17 09:00:00 · 109 阅读 · 0 评论 -
C语言每日一题(30)分割链表
给出一个长度为 n 的单链表和一个值 x ,单链表的每一个值为 list,请返回一个链表的头结点,要求新链表中小于 x 的节点全部在大于等于 x 的节点左侧,并且两个部分之内的节点之间与原来的链表要保持相对顺序不变。将该链表小于x的部分和大于等于x的部分进行拆分分别用两个头结点指向,相当于分别存入两个链表里,最后将链表1(小于x的部分)的尾结点指向链表2(大于等于x的部分)的首结点即可。给出 1→4→3→2→5→2 和 x=3。返回 1→2→2→4→3→5。原创 2023-11-16 09:00:00 · 140 阅读 · 0 评论 -
C语言每日一题(29)合并两个有序链表
11月15日每日一题,合并链表原创 2023-11-15 15:23:55 · 125 阅读 · 0 评论 -
C语言每日一题(28) 反转链表
从头节点开始,将cur->next指向pre,随后将cur指针赋给pre,相当于让pre指向的cur当前的节点,之后再将nex的值赋给cur实现遍历的作用,直到cur为NULL,返回pre即可。给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。经反转后,原链表变为{3,2,1},所以对应的输出为{3,2,1}。pre:用于指向已经完成反转的链表的头节点,最开始指向null。cur:指向链表的当前对应节点,最开始指向头节点。原创 2023-11-11 17:20:41 · 156 阅读 · 0 评论 -
C语言每日一题(27)链表中倒数第k个结点
这是一道经典的快慢指针题,fast和slow最开始都指向头结点,对于输入值k,先让快指针fast先走k步,之后再让两个指针一起走,最后slow指向的就是对应的结点。我的理解就是利用slow与fast的差值形成一个区间,将这个区间进行遍历,当快指针遍历到尾时,相当于从倒数第一个开始往前找slow。输入一个链表,输出该链表中倒数第k个结点。原创 2023-11-09 22:51:50 · 183 阅读 · 0 评论 -
C语言每日一题(26)移除链表元素
针对如图的普通情况,不能简单的遍历到对应位置然后进行释放,一方面会丢掉下一个结点的地址,同时上一个结点的成员指针也会变成野指针。另外一种特殊情况是当头结点就是需要删除的值,如果直接让前一个结点的指针指向该节点的下一个结点,那就是对空指针的非法引用了,是不允许的,所以这里还要再加一个判断条件,即当前一个结点(设为pre)不为空时,让前一个结点的指针指向该节点的下一个结点,否则,直接将下一个结点赋给头结点,因为释放完后头结点也为野指针,此时需要进行赋值。,请你删除链表中所有满足。给你一个链表的头节点。原创 2023-11-08 14:35:25 · 270 阅读 · 0 评论 -
C语言每日一题(25)链表的中间结点
11月7日的每日一题原创 2023-11-08 12:36:18 · 98 阅读 · 0 评论