C语言中链表中经典面试题

🐶博主主页:@ᰔᩚ. 一怀明月ꦿ 

❤️‍🔥专栏系列:线性代数C初学者入门训练题解CC的使用文章「初学」C++

🔥座右铭:“不要等到什么都没有了,才下定决心去做”

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

移除链表元素

反转链表 

合并两个有序链表 

总结 


移除链表元素

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1:

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

示例 2:

输入:head = [], val = 1
输出:[]

示例 3:

输入:head = [7,7,7,7], val = 7
输出:[]

提示:

  • 列表中的节点数目在范围 [0, 104] 内
  • 1 <= Node.val <= 50
  • 0 <= val <= 50

解题思路:

解题的关键在于我们需要大致判断链表的几种情况,然后通过调试,一步一步通过测试用例,这里我们可以分为三种链表,第一种就是链表为空,这种直接返回空指针,第二种就是链表的第一个节点的val值等于测试用例的val,这里我们就需要进行换头处理,就是跳过第一个节点,把第二个节点当作头,第三种val值在链表非头的位置,从头开始寻找,找到等于val的节点,将val的上个节点连接到val的下个节点。因为我们需要知道val的前后两个节点,所以采用双指针的方法

struct ListNode* removeElements(struct ListNode* head, int val)
{
    //这就是第一种情况,如果头为空,直接返回空值
    if(head==NULL)
    {
        return NULL;
    }
    struct ListNode* prev=NULL,*cur=head;//双指针的方法,一前一后的指针
    while(cur)//通过循环遍历整个链表
    {
        if(cur->val==val)
        {
            if(prev==NULL)
            {
                cur=cur->next;
                head=cur;
            }
            else
            {
                prev->next=cur->next;
                cur=cur->next;
            }
        }
        else
        {
            prev=cur;
            cur=cur->next;
        }
    }
    return head;
}

反转链表 

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

示例 2:

输入:head = [1,2]
输出:[2,1]

示例 3:

输入:head = []
输出:[]

提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

解题思路:

解题的关键在于我们需要大致判断链表的几种情况,然后通过调试,一步一步通过测试用例,这题分为两种情况,第一种链表为空的时候,就直接返回空指针,第二种链表不为空时,我们采用的是在原有的链表上进行改动,就是将原有的节点指向改变,这里需要记录三个节点的位置,所以需要三个指针

struct ListNode* reverseList(struct ListNode* head)
{
    if(head==NULL)
    {
        return NULL;
    }
    struct ListNode* n1=NULL;
    struct ListNode* n2=head;
    struct ListNode* n3=head->next;
    while(n2)
    {
        n2->next=n1;
        n1=n2;
        n2=n3;
        if(n3!=NULL)
        {
            n3=n3->next;
        }
    }
    return n1;
}

合并两个有序链表 

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:

输入:l1 = [], l2 = []
输出:[]

示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

提示:

  • 两个链表的节点数目范围是 [0, 50]
  • -100 <= Node.val <= 100
  • l1 和 l2 均按 非递减顺序 排列

解题思路:

解题的关键在于我们需要大致判断链表的几种情况,然后通过调试,一步一步通过测试用例,这个链表分为四种情况,第一种list1为空时,直接返回list2,第二种list2为空时,直接返回list1,第三种list1和list2都为空时,直接返回空指针,第四种list1和list2都不为空时,首先我们的需要一个头指针去保存头节点的位置,我们需要去判断list1和list2的头节点的val值大小情况,谁小就让头指针去指向谁,然后,我们需要遍历两个链表,只要其中一个链表为空,就跳出循环

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
    if(list1==NULL)
    {
        return list2;
    }
    if(list2==NULL)
    {
        return list1;
    }
    if(list1==NULL&&list2==NULL)
    {
        return NULL;
    }
    struct ListNode* cur=NULL;
    struct ListNode* head=NULL;
    while(list1&&list2)
    {
        if(list1->val<list2->val)
        {
            if(head==NULL)
            {
                head=cur=list1;
            }
            else
            {
                cur->next=list1;
                cur=list1;
            }
            list1=list1->next;
        }
        else
        {
             if(head==NULL)
            {
                head=cur=list2;
            }
            else
            {
                cur->next=list2;
                cur=list2;
            }
            list2=list2->next;
        }
    }
    if(list1==NULL)
    {
        cur->next=list2;
    }
     if(list2==NULL)
    {
        cur->next=list1;
    }
    return head;
}

总结 

做链表的题的确需要一番思索,我在做第一个题的时候,做了大概两天时间,但还是没有完全通过测试用例(可能我比较愚笨),我就放弃了这道题。过了几天我重新去做这道题,通过了一些方法,最终解决了这道题。这些方法我归结了一下,可以适用于大部分链表类的测试题,第一:画图!画图!画图!重要的事情说三遍,我感觉之所以之前没有做出来这道题,是我没有认真画图的原因,认真画图非常关键,为什么强调认真画图,我之前做题的时候,就老是把图画的很乱,而且画图的位置空间也不足,导致有时候一次测试用例都没有走完,我就放弃了,后来做题过程中,我就认认真真画图,然后走完了几个测试用例,我就这样完成了这道题。第二:有时候我们感觉逻辑没有问题,但是还是存在错误,我们就需要进行调试了,因为这些题目是在线OJ题,一般是不能调试的,所以我们需要在自己的编译器上进行调试,进行调试后,我们就能很容易的到出错的位置,这样有助于我们完成这道题。

🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸   

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值