链表OJ题(2)

目录

1.移除链表元素√

2.反转链表

3.相交链表

4.链表的中间节点

5.链表中倒数第k个节点

6.合并链表√

7.分割链表√


 今天链表面试OJ题目

  • 移除链表元素
  • 反转链表
  • 相交链表
  • 链表的中间节点
  • 链表中倒数第k个节点
  • 合并链表
  • 分割链表

  • 🙂起始条件 中间节点 结束条件
  • 🙂结束条件while易错
  • 🙂单独处理头和尾
  • 🙂处理链表为NULL的情况
  • 🙂释放的先后顺序-----野指针
  • 🙂指针的指向问题tail / tail->next
  • && ||  == = (赋值)
  • return 返回值的问题
  • 🙂往极端情况考虑

1.移除链表元素√

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

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

【双指针】 

struct ListNode* removeElements(struct ListNode* head, int val) 
{
    struct ListNode*cur=head;
    struct ListNode*prve=NULL;
    while(cur)
    {
        if(cur->val == val)
        {
            if(prve)
            {
                prve->next=prve->next->next;
                free(cur);
                cur=prve->next;
            }
            else
            {
                head=head->next;
                free(cur);
                cur=head;
            }
        }
        else
        {
            prve=cur;
            cur=cur->next;
        }
    }
    return head;
}
cur是指当前节点的指针
prve是指向前一个节点的指针


【三指针不带头节点】

struct ListNode* removeElements(struct ListNode* head, int val) 
{
    struct ListNode* cur=head;
    struct ListNode* tail=NULL;
    struct ListNode* newhead=NULL;
    while(cur)
    {
        if(cur->val != val)
        {
            if(tail)
            {
                tail->next=cur;//易错
                tail=tail->next;
            }
            //处理头
            else
            {
                newhead=tail=cur;//易错
            }
            cur=cur->next;
        }
        else
        {
            struct ListNode* tmp=cur->next;
            free(cur);
            cur=tmp;
        }
    }
    //处理尾
    if(tail)
    {
        tail->next=NULL;
    }
    return newhead;
}


【三指针带头节点】

struct ListNode* removeElements(struct ListNode* head, int val) 
{
    struct ListNode* cur=head;
    struct ListNode* newhead=(struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode* tail=newhead;
    while(cur)
    {
        if(cur->val != val)
        {
            tail->next=cur;
            tail=tail->next;
            cur=cur->next;
        }
        else
        {
            struct ListNode* tmp=cur->next;
            free(cur);
            cur=tmp;
        }
    }
    //处理尾
    if(tail)
    {
        tail->next=NULL;
    }
    struct ListNode*tmp=newhead;
    newhead=newhead->next;
    free(tmp);
    tmp=NULL;
    
    return newhead;
}

2.反转链表

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

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

【头插】

struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode*newhead=NULL;
    struct ListNode*cur=head;
    while(cur)
    {
        struct ListNode*tmp=cur->next;
        cur->next=newhead;
        newhead=cur;
        cur=tmp;
    }
    return newhead;
}
//可以不用处理头
struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode*newhead=NULL;
    struct ListNode*cur=head;
    while(cur)
    {
        struct ListNode*tmp=cur->next;
        if(newhead == NULL)
        {
            newhead = cur;
            newhead->next = NULL;//易错
        }
        else
        {
            cur->next=newhead;
            newhead=cur;
        }
        cur=tmp;
    }
    return newhead;
}


【三指针】

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)
        n3=n3->next;
    }
    return n1;//易错
}


3.相交链表

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

图示两个链表在节点 c1 开始相交

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,6,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
— 请注意相交节点的值不为 1,因为在链表 A 和链表 B 之中值为 1 的节点 (A 中第二个节点和 B 中第三个节点) 是不同的节点。换句话说,它们在内存中指向两个不同的位置,而链表 A 和链表 B 中值为 8 的节点 (A 中第三个节点,B 中第四个节点) 在内存中指向相同的位置。

 【双指针】

  • 题目中有明确的说明两个链表都不为NULL 
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    int A=1;
    int B=1;
    struct ListNode *curA=headA;
    struct ListNode *curB=headB;
    int N=0;
    while(curA->next)
    {
        A++;
        curA=curA->next;
    }
    while(curB->next)
    {
        B++;
        curB=curB->next;
    }
    if(curA != curB)
    {
        return NULL;
    }
    else
    {
        N=abs(A-B);
        if(A>B)
        {
            while(N--)
            {
                headA=headA->next;
            }
            while(headA != headB)
            {
                headA=headA->next;
                headB=headB->next;
            }
            return headA;
        }
        else
        {
            while(N--)
            {
                headB=headB->next;
            }
            while(headA != headB)
            {
                headA=headA->next;
                headB=headB->next;
            }
            return headA;
        }
    }
}

 【简化】

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    int A=1;
    int B=1;
    struct ListNode *curA=headA;
    struct ListNode *curB=headB;
    int N=0;
    while(curA->next)
    {
        A++;
        curA=curA->next;
    }
    while(curB->next)
    {
        B++;
        curB=curB->next;
    }
    if(curA != curB)
    {
        return NULL;
    }
    else
    {
        N=abs(A-B);
        //简写------假设法
        struct ListNode *longlist=headA;
        struct ListNode *shortlist=headB;
        if(B>A)
        {
            longlist=headB;
            shortlist=headA;
        }
        //
        while(N--)
        {
            longlist=longlist->next;
        }
        while(longlist != shortlist)
        {
            longlist=longlist->next;
            shortlist=shortlist->next;
        }
            return longlist;
    }
}

 


4.链表的中间节点

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

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

输入:head = [1,2,3,4,5]
输出:[3,4,5]
解释:链表只有一个中间结点,值为 3 。

【快慢双指针】

  • 保持相对速度
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* middleNode(struct ListNode* head)
{
    struct ListNode*faster=head;
    struct ListNode*slow=head;
    while(faster && faster->next)//条件没想到
    {
        faster=faster->next->next;
        slow=slow->next;
    }
    return slow;
}


5.链表中倒数第k个节点

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

示例1:输入:1,{1,2,3,4,5}

返回值:{5}

示例2:输入:6,{1,2,3,4,5}

返回值:{}


 【快慢指针】 

  • 保持相对距离 

 -----------【k步】

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    struct ListNode*faster=pListHead;
    struct ListNode*slow=pListHead;

    while(k--)//走k
    {
        if(faster == NULL)
        {
            return NULL;
        }
        faster=faster->next;
    }

    while(faster)
    {
        faster=faster->next;
        slow=slow->next;
    }
    return slow;
}

----------------【k-1步】

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 */

/**
 * 
 * @param pListHead ListNode类 
 * @param k int整型 
 * @return ListNode类
 */
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    struct ListNode*faster=pListHead;
    struct ListNode*slow=pListHead;

    while(--k)//走k-1
    {
        if(faster == NULL)
        {
            return NULL;
        }
        faster=faster->next;
    }
    //当循环结束的时候faster为NULL
    if(faster == NULL)//判断一下即可乖乖
    return NULL;

    while(faster->next)
    {
        faster=faster->next;
        slow=slow->next;
    }
    return slow;
}


6.合并链表√

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

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

【三指针带头】

  • 取小尾插
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    struct ListNode*cur1=list1;
    struct ListNode*cur2=list2;
    struct ListNode*newhead=NULL;
    struct ListNode*tail=NULL;
    if(list1 == NULL)
    return list2;
    if(list2 == NULL)
    return list1;
    while(cur1 && cur2)
    {
        if(cur1->val <= cur2->val)
        {
            if(newhead == NULL)
            {
                newhead=tail=cur1;//易错
            }
            else
            {
                tail->next=cur1;//已经放进去//易错
                tail=tail->next;//tail是尾节点,可以往后移动了
            }
            cur1=cur1->next;
        }
        else
        {
            if(newhead == NULL)
            {
                newhead=tail=cur2;
            }
            else
            {
                tail->next=cur2;//已经放进去
                tail=tail->next;//tail是尾节点,可以往后移动了
            }
            cur2=cur2->next;
        }
    }
    if(cur1 == NULL)
    {
        tail->next=cur2;
    }
    else
    {
        tail->next=cur1;//已经不用在往后走了
    }
    return newhead;
}


7.分割链表√

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

【三指针带头】

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
//用不带头节点来写,两个链表都可能为NULL,都要判断非常麻烦
//所以我们用带头节点来写
class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        ListNode* list1=(ListNode*)malloc(sizeof(ListNode));
        ListNode* list2=(ListNode*)malloc(sizeof(ListNode));
        ListNode* tail1=list1;
        ListNode* tail2=list2;
        ListNode* cur=pHead;
        while(cur)
        {
            if(cur->val < x)
            {
                tail1->next=cur;
                tail1=tail1->next;
            }
            else//cur->val >= x
            {
                tail2->next=cur;
                tail2=tail2->next;
            }
            cur=cur->next;
        }
        //尾巴处理
        tail1->next=list2->next;
        tail2->next=NULL;//易错
        return list1->next;
    }
};

 


❓我们√三道题都有异曲同工之妙。

代码---------→【唐棣棣 (TSQXG) - Gitee.com】

联系---------→【邮箱:2784139418@qq.com】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/133896.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

111111111111111

全局锁 就是对整个数据库进行加锁&#xff0c;加锁之后整个数据库就处于只读状态&#xff0c;后续的DML写语句&#xff0c;DDL语句&#xff0c;以及对更新事务的提交操作都会被阻塞&#xff0c;典型地使用场景就是做整个数据库的逻辑备份&#xff0c;对所有的表进行锁定&#x…

动态内存管理(让内存管理更加灵活)

文章目录 概述一、动态内存开辟malloc 函数calloc 函数realloc 函数 二、动态内存释放三、动态内存可能会犯的错误 概述 我们平时在内存中开辟空间的方式有&#xff1a; int a 10;//在栈空间上开辟四个字节int arr[10] {0};//在栈空间上开辟10个字节的连续空间用以上方式开辟…

Clickhouse学习笔记(5)—— ClickHouse 副本

Data Replication | ClickHouse Docs 副本的目的主要是保障数据的高可用性&#xff0c;即使一台 ClickHouse 节点宕机&#xff0c;那么也可以从其他服务器获得相同的数据 注意&#xff1a; clickhouse副本机制的实现要基于zookeeperclickhouse的副本机制只适用于MergeTree f…

【每日一题】情侣牵手

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;并查集 写在最后 Tag 【并查集】【数组】【2023-11-11】 题目来源 765. 情侣牵手 题目解读 返回最少的交换座位的次数&#xff0c;使每对情侣可以坐在一起。 解题思路 方法一&#xff1a;并查集 对于一对情侣&…

跟着openai学编程

装饰者模式 class Component:def operator(self):passclass ConcreteComponent(Component):def operator(self):return "ConcreteComponent operator"class Decorator(Component):def __init__(self, component) -> None:super().__init__()self.component compo…

SDWAN(Software Defined Wide Area Network)概述与优势分析

文章目录 SDWAN简介SDWAN技术优势简化网络部署和维护安全传输灵活网络拓扑极致体验 SD-WAN关联技术STUNIPsec智能选路SaaS路径优化 典型组网多总部分支组网云管理组网 推荐阅读 SDWAN简介 SDWAN&#xff08;Software Defined Wide Area Network&#xff0c;软件定义广域网&…

Java自学第9课:JSP基础及内置对象

目录&#xff1a; 目录 1 JSP基础知识架构 1 指令标识 1 Page命令 2 Including指令 3 taglib指令 2 脚本标识 1 JSP表达式 2 声明标识 3 代码片段 3 JSP注释 1 HTML注释 2 带有JSP表达式的注释 3 隐藏注释 4 动态注释 4 动作标识 1 包含文件标识 2 请求转发标…

vscode 和 keil协同使用开发stm32程序,超详细教程

vscode 和 keil协同使用开发stm32程序 文章目录 vscode 和 keil协同使用开发stm32程序1. 安装vscode拓展安装chinese插件 2 .安装Mingw3.配置环境变量4. 打开Keil项目 VSCODE 是一款广受好评的代码编辑器&#xff0c; KEIL 是常用的嵌入式开发工具但编程界面简陋。 将两个工具…

【PyQt】(自制类)处理鼠标点击逻辑

写了个自认为还算不错的类&#xff0c;用于简化mousePressEvent、mouseMoveEvent和mouseReleaseEvent中的鼠标信息。 功能有以下几点&#xff1a; 鼠标当前状态&#xff0c;包括鼠标左/中/右键和单击/双击/抬起鼠标防抖(仅超出一定程度时才判断鼠标发生了移动)&#xff0c;灵…

TMUX命令的基本操作和使用

tmux&#xff1a;是两个单词的缩写&#xff0c;即“Terminal MultipleXer”&#xff0c;意思是“终端复用器”。 TMUX使用场景&#xff1a;假如你需要跑大模型或者数据集特别大的AI任务时&#xff0c;它往往需要花较长时间才能跑完&#xff0c;在跑的过程中&#xff0c;不能断…

用朴素贝叶斯实现垃圾邮箱分类实验报告

一、实验目的 1.会用Python创建朴素贝叶斯模型 2.使用朴素贝叶斯模型对垃圾邮件分类 3.会把文本内容变成向量 4.会用评价朴素贝叶斯模型的分类效果 二、设备与环境 Jupyter notebook Python3.9 三、实验原理 四、实验内容 1.把给定的数据集message.csv拆分成训练集和测试集&…

LeetCode【207】课程表

题目&#xff1a; 思路&#xff1a; https://www.jianshu.com/p/25868371ddfc/ 代码&#xff1a; public boolean canFinish(int numCourses, int[][] prerequisites) {// 入度int[] indegress new int[numCourses];// 每个点对应的边,出边Map<Integer, List<Intege…

upload 文件自动上传写法,前后端 下载流文件流

<el-uploadv-model:file-list"fileList":action"app.api/student/student/import":headers"{// Content-Type: multipart/form-data;boundary----split-boundary, 此处切记不要加&#xff0c;否则会造成后端报错 Required request part file is…

Python编程:从入门到实践 (项目3—Web应用程序—学习问题汇总)(新手避坑必看)

本人系统环境&#xff1a; WIN10系统 Python 3.9 Django 2.1.5 书本环境&#xff1a; Python 3.x Django 1.8.5 基于Django 开发一个名为“学习笔记”的项目&#xff0c;这是一个在线的日志系统&#xff0c;能够记录所学习的有关特定主题的知识。 建立项目 要编写一个名为“…

第十周学习记录

阅读MARS MARS创新点&#xff1a; (1)实例感知。模拟器使用独立的网络分别对前景实例和背景环境进行建模&#xff0c;以便可以单独控制实例的静态&#xff08;例如大小和外观&#xff09;和动态&#xff08;例如轨迹&#xff09;属性。 (2)模块化。模拟器允许在不同的 NeRF 主干…

补坑:Java的字符串String类(3):再谈String

不太熟悉字符串的可以看看这两篇文章 补坑&#xff1a;Java的字符串String类&#xff08;1&#xff09;-CSDN博客 补坑&#xff1a;Java的字符串String类&#xff08;2&#xff09;&#xff1a;一些OJ题目-CSDN博客 字符串创建对象 public static void main(String[] args) …

compile: version “go1.19“ does not match go tool version “go1.18.1“

** 1 安装了新版本的go后 为什么go version 还是旧版本&#xff1f; ** 如果你已经按照上述步骤安装了新版本的 Go&#xff0c;但 go version 命令仍然显示旧版本&#xff0c;可能是因为你的环境变量设置不正确或未正确生效。你可以尝试以下方法来解决问题&#xff1a; 重新…

YOLOV5改进:RefConv | 即插即用重参数化重聚焦卷积替代常规卷积,无额外推理成本下涨点明显

1.该文章属于YOLOV5/YOLOV7/YOLOV8改进专栏,包含大量的改进方式,主要以2023年的最新文章和2022年的文章提出改进方式。 2.提供更加详细的改进方法,如将注意力机制添加到网络的不同位置,便于做实验,也可以当做论文的创新点 3.涨点效果:RefConv,实现有效涨点! 论文地址 …

优雅关闭TCP的函数shutdown效果展示

《TCP关闭的两种方法概述》里边理论基础&#xff0c;下边是列出代码&#xff0c;并且进行实验。 服务端代码graceserver.c的内容如下&#xff1a; #include "lib/common.h"static int count;static void sig_int(int signo) {printf("\nreceived %d datagrams\…

nature日报:为什么印度德里现在的空气污染如此严重?

为什么印度德里现在的空气污染如此严重&#xff1f; 后季风季节为印度大城市的空气污染积累创造了理想的条件。 本文整理扩展自2023年11月10日nature杂志的NEWS EXPLAINER——Why is Delhi’s air pollution so bad right now? (nature.com) Highlights 季风期间&#xff0…