(C语言版)力扣(LeetCode)+牛客网(nowcoder)链表相关面试题OJ题解析(上)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析DNS,个人版 1个月
全局流量管理 GTM,标准版 1个月
简介: 递归的写法看起来简洁,实际并没有迭代写法好理解,而且在空间复杂度上也比迭代高,这里的递归写法思路主要是先向下找到尾结点后,向上逐个返回,如果等于val值,就将该节点上一个元素直接指向该节点下一个元素,等于是将该点从链表中删除了

5a9e9ab2ae0e45b3b81ed2eac2d9fa3d.png


203. 移除链表元素


题目


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

题目链接:移除链表元素


解法一:递归


代码如下:


struct ListNode* removeElements(struct ListNode* head, int val){
    if(head==NULL)
        return NULL;
    head->next=removeElements(head->next,val);
    return head->val==val?head->next:head;
}


递归的写法看起来简洁,实际并没有迭代写法好理解,而且在空间复杂度上也比迭代高,这里的递归写法思路主要是先向下找到尾结点后,向上逐个返回,如果等于val值,就将该节点上一个元素直接指向该节点下一个元素,等于是将该点从链表中删除了

如下图:

3e6f948498a440439162e2f05d3f72b5.png


解法二:迭代


代码如下:


struct ListNode* removeElements(struct ListNode* head, int val){
    struct ListNode* headhead=malloc(sizeof(struct ListNode));
    headhead->next=head;
    struct ListNode* temp=headhead;
    while(temp->next!=NULL)
    {
        if(temp->next->val==val)
            temp->next=temp->next->next;
        else
            temp=temp->next;
    }
    return headhead->next;
}


迭代的思路就比较好理解了,先创建一个结点空间headhead,让它指向head,再用temp复制该内存地址,使用temp对链表进行遍历,找到等于val值的元素就删除,直至遍历完整个链表,最后headhead指向的下一个位置即为删除val结点的head头结点位置。


206. 反转链表


题目


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

题目链接:反转链表


解法一:递归


代码如下:


struct ListNode* reverseList(struct ListNode* head) {
    if (head == NULL || head->next == NULL) {
        return head;
    }
    struct ListNode* newHead = reverseList(head->next);
    head->next->next = head;
    head->next = NULL;
    return newHead;
}


这里的递归写法相对于上一题更不好理解一些,具体也是向下找到最后一个结点,逐个反转,如下图:


0b4cda31fbce4752ab196cc809b47f14.png


解法二:迭代


代码如下:


struct ListNode* reverseList(struct ListNode* head){
    struct ListNode* prev=NULL;
    struct ListNode* cur=head;
    while(cur)
    {
        struct ListNode* next=cur->next;
        cur->next=prev;
        prev=cur;
        cur=next;
    }
    return prev;
}


迭代写法就很简单了,设定两个指针,prev指向NULL,cur指向头结点,再用循环从头开始反转,最后prev即为头结点,返回prev即可。


876. 链表的中间结点


题目


给你单链表的头结点 head ,请你找出并返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

题目链接:链表的中间结点


解法一:快慢指针法


代码如下:


struct ListNode* middleNode(struct ListNode* head){
struct ListNode* fast = head;
struct ListNode* slow = head;
while(fast&&fast->next)
{
    slow=slow->next;
    fast=fast->next->next;
}
return slow;
}


个人觉得快慢指针的写法更简洁且好理解,大概的思路就是slow指针走一步,fast指针走两步,fast遍历完链表,slow指针指向的即为中间结点。


解法二:单指针法


代码如下:


struct ListNode* middleNode(struct ListNode* head){
    int n=0;
    struct ListNode* cur=head;
    while(cur!=NULL)
    {
        n++;
        cur=cur->next;
    }
    int k=n/2;
    cur=head;
    while(k>0)
    {
        cur=cur->next;
        k--;
    }
    return cur;
}


这个算法的思路就是用cur指针先遍历一遍数组,用n记录结点个数,再用结点数/2的值赋给k,cur重新指向头结点,再进行遍历k个位置,最后cur停在的结点位置即为中间节点位置。


链表中倒数第k个结点


题目


输入一个链表,输出该链表中倒数第k个结点。

题目链接:链表中倒数第k个结点


解法


代码如下:


struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    struct ListNode* fast=pListHead;
    struct ListNode* slow=pListHead;
    while(k--)
    {
        if(fast==NULL)
        {
            return NULL;
        }
        fast=fast->next;
    }
    while(fast)
    {
        fast=fast->next;
        slow=slow->next;
    }
    return slow;
}


这里用的是双指针的写法,先让fast指针向前走k个结点位置,再让fast和slow同时走,直到fast走到NULL,此时的slow指向的就是倒数第k个结点。


21. 合并两个有序链表


题目


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

题目链接:合并两个有序链表


解法一:递归


代码如下:


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


这种递归写法相对好理解一些,前两个条件是考虑list1或list2为空的情况发生,后两个条件都是使用递归,当list1头结点值小于list2头结点值时,则头结点为list1,否则为list2,然后继续向下一结点递归,最后合并完整个链表。


解法二:迭代


代码如下:


struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    struct ListNode* list3=(struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode* p3=list3;
    while(list1!=NULL&&list2!=NULL)
    {
        if(list1->val<list2->val)
        {
            p3->next=list1;
            list1=list1->next;
            p3=p3->next;
            p3->next=NULL;
        }
        else
        {
            p3->next=list2;
            list2=list2->next;
            p3=p3->next;
            p3->next=NULL;
        }
    }
    if(list1==NULL)
        p3->next=list2;
    if(list2==NULL)
        p3->next=list1;
    return list3->next;
}


这种写法的思路是借助额外的空间,也是逐个比较大小,再将结点从小到大串联,最后返回额外的空间结点指向的下一结点,即为调整好的链表。

相关文章
|
2月前
|
存储 算法 安全
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
43 0
|
3月前
|
算法 Java 调度
《面试专题-----经典高频面试题收集四》解锁 Java 面试的关键:深度解析并发编程进阶篇高频经典面试题(第四篇)
《面试专题-----经典高频面试题收集四》解锁 Java 面试的关键:深度解析并发编程进阶篇高频经典面试题(第四篇)
47 0
|
23天前
|
C语言
C语言操作符(补充+面试)
C语言操作符(补充+面试)
27 6
|
10天前
|
算法 C语言
【面试题】【C语言】寻找两个正序数组的中位数
【面试题】【C语言】寻找两个正序数组的中位数
9 0
|
2月前
|
安全 Java 开发者
Java面试题:Java内存模型解析,Java内存模型的基本概念和它的重要性,Java内存模型中的“可见性”和“有序性”,以及具体实现?
Java面试题:Java内存模型解析,Java内存模型的基本概念和它的重要性,Java内存模型中的“可见性”和“有序性”,以及具体实现?
39 1
|
2月前
|
存储 数据管理 C语言
C语言实战 | 使用链表完成“贪吃蛇”游戏
【7月更文挑战第1天】整体思维,即系统思维,强调以整体视角理解事物。在编程中,结构体体现这种思想,将相关变量打包处理。示例展示了如何用链表而非数组实现“贪吃蛇”游戏,链表提供了更灵活的动态数据管理。一系列代码图片详细描绘了链表结构体在游戏中的应用,包括节点定义、移动、碰撞检测等,凸显了使用链表的优势和代码的清晰组织。
30 0
C语言实战 | 使用链表完成“贪吃蛇”游戏
|
2月前
|
存储 安全 Java
Java面试题:Java内存管理、多线程与并发框架:一道综合性面试题的深度解析,描述Java内存模型,并解释如何在应用中优化内存使用,阐述Java多线程的创建和管理方式,并讨论线程安全问题
Java面试题:Java内存管理、多线程与并发框架:一道综合性面试题的深度解析,描述Java内存模型,并解释如何在应用中优化内存使用,阐述Java多线程的创建和管理方式,并讨论线程安全问题
22 0
|
2月前
|
存储 并行计算 安全
Java面试题:Java内存管理、多线程与并发框架的面试题解析与知识点梳理,深入Java内存模型与垃圾回收机制,Java多线程机制与线程安全,Java并发工具包与框架的应用
Java面试题:Java内存管理、多线程与并发框架的面试题解析与知识点梳理,深入Java内存模型与垃圾回收机制,Java多线程机制与线程安全,Java并发工具包与框架的应用
43 0
|
2月前
|
Python
155. 最小栈 力扣 python 空间换时间 o(1) 腾讯面试题
155. 最小栈 力扣 python 空间换时间 o(1) 腾讯面试题
|
2月前
|
存储 算法 索引
1124. 表现良好的最长时间段 (python) 前缀和 分类讨论 最大长度 力扣 面试题
1124. 表现良好的最长时间段 (python) 前缀和 分类讨论 最大长度 力扣 面试题

推荐镜像

更多
下一篇
云函数