【真实面试】找错误:面试某大厂手写链表题,找找他错在哪里了?
本问题对应课程链接:剑指offer刷题第二期
这是一个读者面试某大厂时,在线写 删除链表倒数第 n 个节点的算法题,不过我说过,链表题很容易出错,他也是犯了致命错误。
现在考验一下大家,大家看看他的代码错在哪里?
打卡:找出他哪里错了
本问题对应课程链接:剑指offer刷题第二期
这是一个读者面试某大厂时,在线写 删除链表倒数第 n 个节点的算法题,不过我说过,链表题很容易出错,他也是犯了致命错误。
现在考验一下大家,大家看看他的代码错在哪里?
打卡:找出他哪里错了
共以下 62 个回答
1.fast边界
2.用虚拟节点好一点,不用特判
没有考虑边界 可以加一个虚拟表头
没有考虑到空指针的问题,特别是当链表只有一个节点的时候,pre->next = slow->next明显会报错。
仅有一个结点的时候,pre->next会报错,空指针异常。
边界性问题,没有删除头节点操作
1、代码写的太难看了
2、不规范,考虑不全
可能为空
没考虑空指针异常
边界处理
fast 可能会遍历到null
以前踩过坑的题目
坑就是不能保证链表可以取到第n个结点
也就是没有考虑如果fast没有走到第n个的情况
没有考虑快指针可能为空
没有考虑当k大于等于链表的长度。当k>=链表长度时,快指针会发生空指针异常。
边界异常
应该弄个虚拟头节点,这样如果删除的是头节点的话就不用进行特殊处理了
没有对参数n的边界做处理,n有可能大于链表的节点个数,这时候fast指针等于空,while(n–) { if(fastNULL) return head; fast = fast->next;
}
1.如果n大于链表长度,会置空
空指针异常
当n的大小等于链表长度时会遍历到null节点,此时pre未初始化
最后快节点会为null
未考虑当传入的n刚好是链表长度或者大于,这样就会导致空指针异常
如果n = 链表长度,是要删除头结点,此时无法进行删除,需要用到虚拟头结点
面试官好敷衍啊,还说代码写得很好
当n的大小等于链表长度时会遍历到null节点,此时pre未初始化
正确解决方式:添加虚拟头结点
当n>链表长度时,是不是会删除头指针
应该是没有考虑n大于链表长度和应该从n-1开始–做为while的判断条件
当
sizen时会段错误没有考虑到倒数第n个节点是头节点或者甚至n是大于链表长度的情况
在未使用虚拟头结点的情况下,没有对删除的节点是头结点这种情况做特殊处理即sz等于n时。提示中有sz小于等于n,不用考虑fast指针指空的情况。
第一个while循环应进行判空,k有可能大于链表长度,导致fast指向空,进而使头结点被删除。
没有考虑倒数第n个节点为头结点时的情况,应该用先创建一个虚拟头结点,让虚拟头结点 dummyHead.next = head
第一个while没考虑Fast为空, 第二个while要是不执行的话,好像后面pre.next也空指针了,
先定义虚拟头结点,遍历n次,同时后移,返回虚拟头结点的next
没有判断n为链表长度的情况,导致fast为空
时间复杂度:O(n)
空间复杂度:O(n)
时间复杂度O(n)
空间复杂度O(1)
考虑辅助头节点,有可能删除的节点为头节点
边界问题
没有考虑删除头节点的情况,这里我用虚拟头节点
fast先移动的时候没有考虑fast可能为空的情况
fast应该先移动n+1步
没有考虑,n等于链表长度的情况。fast可能会为空。
边界问题没有考虑
没有考虑删除的节点为头节点的情况
边界问题没有考虑
没考虑中间fast指针可能指向空
如示例2,按照他的代码,while(fast)的循环不会走,pre节点没有被赋值,循环外的pre节点引用会报错
需要考虑n为链表长度,即要删除节点为头节点的情况
解体思路:使用快慢指针,fast指针移动n次之后,fast和slow同时移动直到fast移动到尾节点,此时slow指向要删除的倒数第n个节点,删除即可,考虑要删除的节点为头节点的情况,返回head.next
时间复杂度:O(n)
空间复杂度:O(1)
边界问题,只有一个数据和删除第一个数据的情况
边界问题,还有就是用一个节点之前首先判断它非空
没有考虑删除节点是头节点的情况?
私以为删除某个节点,应当找到该节点的前一个节点来进行操作
另外边界处理的地方也是大问题,应当固定边界判别的思维习惯,是指向最后一个节点,还是指向最后一个节点的后一个节点
没有判断pre为NULL,若pre为NULL,后面pre->next报错
删除头节点的时候pre为空,需要添加虚拟头节点。
我的思路比较简单暴力,边界问题,长度相同的倒数节点的处理,我的处理方法就是单独拎出来进行处理,代码比较丑陋。。。。
在不增加头结点的情况下改良这个代码,需要在第一个while后判断fast是否为空,如果为空则直接返回head.next;其他都是对的。我也挂了,下次一定记住加一个头结点:(
若删除倒数第链表长度个结点,经过第一个while循环后fast指针为空,第二个while循环不会执行。此时pre为空,pre->next会报错。
个人感觉是fast多走了一步
判断条件写得不对,应该判断为空,为空的时候跳出循环,遍历找节点时地址为空时停止,在头结点和尾部处理时关注其值是否为空,在执行操作,可以通过虚拟节点即哨兵来解决这个边界问题
如果一共n个节点,删除倒数第n个节点也就是第一个节点会空指针异常,pre最开始指向null,slow指向head,不存在null.next=slow.next,会造成空指针异常,因此需要一个虚拟头节点指向头节点,pre指针虚拟头节点,slow指向head节点,然后思路和他一样就没事了。
而且它最开始的if判断也没判断对,紧张了
倒数第一个节点fast可能为null,slow也可能为null,slow.next又是空指针异常,while循环那改成fast.next
嘴说还是不靠谱直接再上代码
直接上代码,这个操作很稳
第一个while循环如果n = sz,循环结束fast指向null为空,第二个循环就不会执行
在删除节点的时候没有考虑到null的情况,可以重新定义一个哑节点去处理,或者可以不处理,直接输出结果。
fast不为空
本人比较菜,只找到了一个地方,还是根据视频中的提示才找到。就是面试官问fast指针会不会空的时候,确实是有可能会空的。
比如说,当链表结点长度为3的时候,如果要删除链表中倒数第3个结点(头节点),那么在一开始while(n—) fast=fast->next;就会往后走3步,但是fast一开始是指向head是就是第1个结点。也就是说它最多能走2步,再多走一步就会是空指针。
交流一下,fast是可以为空的,只是这个程序删除头节点有问题。可以定义一个虚拟头节点dummyHead,dummyHead.next=head;然后定义要删除倒数第n个节点的前驱节点为pre,pre=dummyHead,然后定义一个快指针fast=head,fast先走n步,然后和pre同时走,当fast指向null时,说明fast已经遍历完链表,而pre正好指向倒数第n个节点的前驱节点,也就是倒数第n+1个节点,然后让pre.next = pre.next.next(n不等于0,pre.next就不指向空,这里可以加个判断条件,防止不合法输入)以此来删除倒数第n个节点,然后返回dummyHead.next。
我是Java语言的,C++了解的不多,先说下我找的错误。
1.先说下我找到的他最后修改后的代码第一个明确错误,当链表中只有一个节点,经过两个while(),pre=null,pre->next = slow->next就会报错。
2.再说下我看他刚开始写犯的错误,首先没有判断头节点为空的情况,其次第一次返回的是要删除的节点(第一次面试可能有些紧张)。
写程序时可以注意一些特殊输入,比如空链表,只含一个节点的链表,可以在fast指针走时也判断下fast是否为空。
讨论交流一下
第一行代码的意思是当head为空的时候返回head
视频中好像是返回了head,delete了slow
感谢解答。我是边看边找,这个主要是程序边界值没处理好,比如空链表,只含一个节点的链表。