牛客网常见算法思路 (五)链表

难度不高主要是代码实现能力
关键点:返回值 返回节点类型、建议先画图的方式理清逻辑、注意特殊值,空、头、尾
插入删除注意事项,注意空链表和长度为1的链表(要多练习熟能生巧)
链表翻转注意事项,单链表翻转时记得不要出现有地址丢失的现象(有指针指向now节点的下一个节点节点才行)
最优解往往不使用额外的数据结构、

熟练写出链表逆序的代码,用好多了

TYPE *reverse(TYPE *head)
{
    TYPE *pre=NULL,*p=NULL,*latter=NULL;
    
    pre = head;
    p=pre->next;
    while(p != NULL)
    {
        latter = p->next;
        p->next = pre;
        pre = p;
        p = latter;
    }
    head->next = NULL;
    head=pre;
    
    return head;
}

案例一

要求:
给定一个整数num如何保证节点值 有序的环形链表中插入一个节点值为num的节点,并且保证这个环形单链表依然有序
思路:
1链表为空,node->var=num; node->next=node,返回node
2若node.var<head.var直接插入head前面,此时node节点为head节点,返回node节点
3有两个以上时,pre指向头结点,curr指向第二个节点,同步移动,若p.var<=node.var且.curr.var>=node.var,则将node插入到p和c之间,返回head即可
4若pc转了一圈都没发现应该插入的位置(curr=head),node插在头结点前面,返回head节点

案例二

要求:
给定一个链表中的节点node,但不给定整个链表的头结点,如何在链表中删除node?请实现这个函数,要求时间复杂度为O(1)
思路:
双向链表:pre节点和next节点重新连接即可
单链表:无法找到前一个节点(前面部分不可见),如1->2->3->4->5->null,删2,因为1不可见,所以将2复制next节点的值3,3复制next节点的值4如此类推,过程中next->next=null就直接删除后一个节点
但这样无法处理给出的节点是最后一个节点的情况,如果给定节点6并且要删除,没有下一个节点可以复制,由于对前面不可见无法将节点4指向null。
评价:本质上不是删除节点而是拷贝,结构复杂时且拷贝操作受限时,不可行,且工程上有可能有外部依赖,删除很麻烦不可取(删除节点2时实际上删除节点3)

案例三

要求:
给定头结点head,再给定一个数num,把链表调整成节点值 小于num的放链表左边,大于num都放右边
思路:
简单做法:所有数放数组,数组进行快排划分,再依次连接
最优解:分三条链表,大于num的 等于num的 小于num的,再将三条链表合并,只是考察代码实现能力

案例四

要求:
给定两个有序链表头结点head1和head2,打印公共部分
思路:
1、有一个为空,直接打印空
2、指针c1 c2,如果c1.val<c2.val,c1->next,同理,谁小谁往后挪,相同则打印,其中一个null,过程停止

案例5

要求:
给定一个有n个节点的单链表头结点head,是实现一个调整单链表的函数,使得每个K节点之间逆序,如果最后不够K个节点一组,则不调整最后的几个节点
12345678->123 456 78->32165478
思路:
若n=0,1,2,直接返回
方法一:时间复杂度O(n),空间O(K)
元素依次进栈,凑齐K个就弹出,对代码实现有要要求,记录第一组头结点以及上一组已完成的尾结点
方法二:(最优解)时间复杂度O(n),空间(1)
直接在链表上操作,凑齐k个就逆序调整,但要考虑更多的代码实现

案例6

要求:
给定单链表头结点head,链表中每个节点保存一个整数,再给定一个值val,把所有等于val的节点删掉
思路:
创造一个新链表一节head,tail指针,不是num就放进该链表,动态更新tail,注意边界值
(个人感觉这没必要吧,好像可以在原来链表的基础上删除的)

案例7

要求:
判断链表是否为回文结构
思路:
方法123时间都为O(n),空间为O(n) O(n/2) O(1)
方法1,创造一个栈,依次复制链表进栈,弹出时依次对比链表
方法2,创造一个栈,设定快指针和慢指针,快指针依次走2部,慢指针依次走一步,并复制节点值入栈,当快指针走完时,慢指针刚好到一半,若链表长为基数则不放最后一个指针,此时栈里的元素为左部分的逆序,此时栈弹出,而慢指针依次遍历,同时对比
方法3,找出中间节点,右边部分链表逆序,然后从两边开始遍历对比,但返回之前必须将链表右边的值逆序回来

案例8

要求:一个链表结构中,每个节点不仅好友一条指向下一个节点的next指针,还有一条rand指针,rand指向随机,请复制这种链表
思路:(先复制在分流可以避免rand指针指向的值新链表还没复制到)
1、长度为0,1直接返回
2、从头开始遍历节点,把节点按next的顺序拷贝,并且放在本身与next之间,例:123null->1 1’ 2 2’ 3 3’ null
3、从头开始遍历,1的rand是3的话,将1’的rand指向3’,
4,链表分流即可

案例9

要求:
如何判断一个单链表是否有环?如果有环返回进入环的第一个接节点,无环的话返回空,时间O(N),空间O(1)
思路:
若无空间限制最简单可以用hash表实现,无环的话直走到结尾也不会重复,有环返回第一个重复节点即可
最优解:头结点开始用快慢指针遍历,快指针一次两步,慢指针依次一步,如果无环则会快速到达null,若有环则会快慢环中相遇则证明有环,此时快指针从头开始遍历,再次相遇时为进入环的节点

案例10

要求:
判断俩无环单链表是否相交,相交的话返回第一个相交的节点,否则返回空,时间复杂度(N+M),空间O(1)
思路:
若无空间限制,使用hash表,先遍历1再遍历2即可
最优解,遍历各自的链表,统计长度,N M 设N>M
此时N的链表先走N-M步,再同时开始,相同节点则相交

案例11

要求:
判断有环单链表是否相交,相交返回第一个相交节点,否则返回空,时间复杂度(N+M),空间O(1)
思路:
1、先依照案例9找到各自入环节点,a,b
2、若a=b则必定相交
3、依照案例10,从head直到各自入环节点前,先判断是否在该段已经相交
4、
在这里插入图片描述
在这里插入图片描述
回到本身入环节点之前没有碰到另一个入环节点,返回空,碰到则返回入环节点1或者返回入环节点2都正确

案例12

思路:
给定两个单链表的头结点head1和head2,如何判断两个链表是否相交,相交的话返回第一个相交的节点,否则返回空
1、判断是否有环(案例9),一个有环一个无环则不可能相交
2、 都无环,案例10
3、都有环,案例11

发布了11 篇原创文章 · 获赞 14 · 访问量 250

猜你喜欢

转载自blog.csdn.net/weixin_44303896/article/details/104027642