单链表算法经典OJ题

news2024/11/14 5:41:40

目录

1、移除链表元素 

2、翻转链表 

3、合并两个有序链表 

4、获取链表的中间结点 

5、环形链表解决约瑟夫问题 

6、分割链表 


1、移除链表元素 

203. 移除链表元素 - 力扣(LeetCode)

typedef struct ListNode LSNode;
struct ListNode* removeElements(struct ListNode* head, int val){
    LSNode* newHead,*newTail;
    //令头结点和尾结点都置为空
    newHead = newTail = NULL;
    //令新指针pcur指向原链表的头结点head,遍历原链表
    LSNode* pcur = head;
    while(pcur)
    {
        //当不满足.val==val时,开始向新建的空链表中插入
        if(pcur->val != val)
            {
                //1、如果新建的链表为空,插入的新节点就是链表的头结点和尾结点
                if(newHead == NULL)
                    {
                        newHead = newTail = pcur;
                    }
                //2、如果新建的链表不为空,直接尾插,让新插进来的结点作为新的尾结点
                else
                    {
                        newTail->next = pcur;
                        newTail = newTail->next;//令newTail移位
                    }
            }
        //当满足pcru->val = val,直接跳过进行下一个读取即可
        pcur = pcur->next;
    }
    //当pcur指向存储整数6的结点时,pcur满足pcur.val = val不会进入if,直接执行pcur = pcur->next,此时pcur = NULL
    //pcur为NULL,跳出while循环,如果此时直接返回newHead那么新链表的newTail->next指向的位置仍是旧链表存储数据6
    //的结点,所以此时需要再判断newTail是否为空,如果不为空则让它最后指向的方向置为空,最后再返回头结点
    if(newTail)
        newTail->next = NULL;
    return newHead;
}

2、翻转链表 

 206. 反转链表 - 力扣(LeetCode)

typedef struct ListNode LSNode;
struct ListNode* reverseList(struct ListNode* head)
{
    //如果传入的链表为空的时候直接返回NULL
    if(head == NULL)
    {
        return NULL;
    }
     LSNode* n1,*n2,*n3;
     n1 = NULL; n2 = head;n3 = head->next;
     while(n2)
     {
         n2->next = n1;
         n1 = n2;
         //当n3为空时已经将n3的值交给n2
         n2 = n3;
         //当n3所处的位置不为空时才能接着移动n3,否则结束一次while循环
         if(n3)
            n3 = n3->next;
     }
     //此时n1为链表的头
    return n1;
}

3、合并两个有序链表 

 21. 合并两个有序链表 - 力扣(LeetCode)

typedef struct ListNode LSNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
    //当传入的两个链表其中有一个为空,那么返回另一个链表即可
    if(list1 == NULL)
    {
        return list2;
    }
    if(list2 == NULL)
    {
        return list1;
    }

    //当两个链表都不为空时,遍历链表
    LSNode* cur1 = list1;
    LSNode* cur2 = list2;
    //创建新的空链表--带头(结点)单向不循环链表(后续进行尾插等情况就不需要考虑头结点是否为空的情况,减少重复代码)
    LSNode* newHead,*newTail;
    //malloc创建一个内存空间,该空间不含有效数据,刚好用于存放该链表的头结点(头结点的有空间但是不存储有效数据)
    newHead = newTail = (LSNode*)malloc(sizeof(LSNode));
    //当两个结点有一个走到空就不能进行比较了
    while(cur1 && cur2)
    {
        //把值小的结点尾插到新的链表
        if(cur1->val < cur2->val)
            {
            newTail->next = cur1;
            newTail = newTail->next;
            cur1 = cur1->next;
            }
        //当cur2->val <= cur1->val时
        else
        {
            newTail->next = cur2;
            newTail = newTail->next;
            cur2 = cur2->next;
        }
    }
if(cur1)
    newTail->next = cur1;
if(cur2)
    newTail->next = cur2;
return newHead->next;
}

4、获取链表的中间结点 

876. 链表的中间结点 - 力扣(LeetCode)

typedef struct ListNode LSNode;
struct ListNode* middleNode(struct ListNode* head)
{   
    if(head == NULL)
        return NULL;
    
    //快慢指针
    LSNode* slow,*fast;
    slow = fast = head;
    //只要fast和fast->next有一个为空则停止循环
    //因为我们也不知道链表的结点数是奇数还是偶数
    while(fast && fast->next)
    //注意二者判断顺序不能交换,因为如果链表结点数为偶数时最后一次循环 
    //fast指向的位置刚好空,下次循环前判断时,由于fast以及指向空了,更别提fast->next了
    //虽然此时slow指向了我们想要的位置但是由于fast->next本身就不合理程序就会报错
    //当然如果是奇数个就可以交换
    {
        slow = slow->next;
        fast = fast->next->next;
    }
    //当循环结束时,slow必定指向我们要找的链表中间结点
    return slow;
}

5、环形链表解决约瑟夫问题 

环形链表的约瑟夫问题_牛客题霸_牛客网 (nowcoder.com)

#include <stdio.h>
#include <stdlib.h>
typedef struct ListNode ListNode;

//申请链表结点函数,同时为结点中添加数据x
ListNode* ListByNode(int x)
{
    ListNode* node = (ListNode*)malloc(sizeof(ListNode));

    if(node == NULL)
    {
        perror("malloc fail!");
        exit(1);
    }
    node->val = x;
    node->next = NULL;
    return node;
}

//创建带环链表
ListNode* CreateList(int n)
{
    ListNode* phead = ListByNode(1);
    ListNode* pTail = phead;
    for(int i = 2;i<=n;i++)
    {
        ListNode* node = ListByNode(i);
        pTail->next = node;
        pTail = pTail->next;
    }
    //以上只是在创建单链表,想要让链表成环,需要将尾结点和头结点相连
    pTail->next = phead;
    //这里直接返回尾结点因为有尾结点就能直接找到头结点,返回头结点的话还需要遍历链表才能找到尾结点
    return pTail;
}

//实现函数
int ysf(int n, int m ) {
    //创建不带头单向循环链表
    ListNode* prev = CreateList(n);
    //进行游戏逻辑实现
    ListNode* cur = prev->next;//就是头结点
    int count = 1;
    while (cur->next != cur) 
    {
        if(count == m)
        {
            //删除结点
            prev->next = cur->next;
            free(cur);
            cur = prev->next;
            count = 1;//人死后记得让下一个人从1开始报数(count重置为初始值1)
        }
        else 
        {
            //继续向下报数
            prev = cur;
            cur = cur->next;
            count++;
        }
    }
    //此时链表中只剩下一个结点,返回该结点中的数
    return cur->val;
}

6、分割链表 

面试题 02.04. 分割链表 - 力扣(LeetCode) 

typedef struct ListNode ListNode; 
struct ListNode* partition(struct ListNode* head, int x)
{
    if(head == NULL)
        return head;
    
    //创建带头的大小链表
    ListNode* lessHead,*lessTail;
    ListNode* greatHead,*greatTail;

    //创建大小链表的哨兵位
    lessHead = lessTail = (ListNode*)malloc(sizeof(ListNode));
    greatHead = greatTail = (ListNode*)malloc(sizeof(ListNode));

    //遍历原链表,将结点放到大小链表中
    ListNode* cur = head;
    //当cur读取原链表后循环结束
    while(cur)
    {   
        //放入小链表
        if(cur->val < x)
        {
            lessTail->next = cur;
            lessTail = lessTail->next;
        }
        //放入大链表
        else
        {
            greatTail->next = cur;
            greatTail = greatTail->next;
        }
        cur = cur->next;  //cur向后走
    }
    //原链表循环结束此时greatTail后指向的内容并未被置空所以要判断
    if(greatTail)
        greatTail->next = NULL;
    //小链表的尾和大链表的哨兵位的下一个结点连接起来
    lessTail->next = greatHead->next;
    return lessHead->next;
}

~over~ 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI原生时代,一场彻底的“智能”觉醒

【潮汐商业评论/原创】 “你用‘AI’工作过吗&#xff1f;” 这往往是Freya向别人吐槽的第一句。 在使用各种版本语言大模型的过程中&#xff0c;Freya与人工智能的交流往往就像两个相切的圆&#xff0c;有交集&#xff0c;但又好像没有&#xff0c;双方你问你的&#xff0c…

mysql同时使用order by排序和limit分页数据重复问题

目录 场景再现&#xff1a; 解决方案&#xff1a; 问题分析&#xff1a; mysql官方描述&#xff1a; 场景再现&#xff1a; 最近排查数据时发现使用order by及limit分页时会出现不同页数数据重复问题及有的数据分页不会显示,但是按条件搜索就可以搜索出来。 解决方案&#x…

软件评测师之操作系统基础知识

目录 一.操作系统的概述二.P、V、S机制(1)进程控制(2)原语(3)互斥(4)同步(5)临界资源(6)临界区 三.三态模型四.死锁五.进程资源图六.文件管理多级目录结构 七.存储管理1.页式存储2.段式存储3.段页式存储 一.操作系统的概述 作用&#xff1a;管理硬件资源&#xff0c;改善人机交…

2000-2022年上市公司CEO 高管及董事会环保背景数据(5W+ )(原始数据+处理代码Stata do文档)

2000-2022年上市公司CEO 高管及董事会环保背景数据&#xff08;5W &#xff09;&#xff08;原始数据处理代码Stata do文档&#xff09; 1、时间&#xff1a;2000-2022年 2、指标&#xff1a;证券代码、股票代码、年份、股票简称、ST或PT为1&#xff0c;否则为0、金融业为1&a…

并发容器(Map、List、Set)实战及其原理

一. JUC包下的并发容器 Java的集合容器框架中&#xff0c;主要有四大类别&#xff1a;List、Set、Queue、Map&#xff0c;大家熟知的这些集合类ArrayList、LinkedList、HashMap这些容器都是非线程安全的。 所以&#xff0c;Java先提供了同步容器供用户使用。 同步容器可以简单地…

【C++面向对象】2.构造函数、析构函数

文章目录 【 1. 构造函数 】1.1 带参构造函数--传入数据1.2 无参构造函数--不传入数据1.3 实例1.4 拷贝构造函数 【 2. 析构函数 】 【 1. 构造函数 】 类的构造函数是类的一种特殊的成员函数&#xff0c;它会 在每次创建类的新对象时执行。 构造函数的名称与类的名称是完全相同…

ARM可用的可信固件项目简介

安全之安全(security)博客目录导读 目录 一、TrustedFirmware-A (TF-A) 二、MCUboot 三、TrustedFirmware-M (TF-M) 四、TF-RMM 五、OP-TEE 六、Mbed TLS 七、Hafnium 八、Trusted Services 九、Open CI 可信固件为Armv8-A、Armv9-A和Armv8-M提供了安全软件的参考实现…

MT8195/MTK8195安卓核心板-安卓智能模块

MT8195安卓核心板是一款先进的处理器&#xff0c;采用了台积电的6纳米制程技术。它由4个Cortex-A78大核和4个Cortex-A55小核组成&#xff0c;搭配Mali-G57MC5 GPU和APU 3.0&#xff0c;算力高达4 TOPs。该核心板支持四通道LPDDR4X 2133MHz内存&#xff0c;具备出色的性能。此外…

java并发编程之基础与原理1

java多线程基础 下面说一下线程的7种状态 下面我重点来说一下阻塞状态 阻塞状态是可以分很多种的&#xff1a; 下面用另外一张图来说明这种状态 简单说一下线程的启动原理 下面说一下java中的线程 java线程的异步请求方式 上面就会先把main执行出来&#xff0c;等阻塞结束之后…

变化检测数据集制作详细版

本文记录在进行变化检测数据集制作过程中所使用的代码 首先需要准备相同地区不同时间的两幅影像&#xff0c;裁减成合适大小&#xff0c;如256*256。相同区域命名相同放在两个文件夹下。 接着使用labelme对变化区域进行标注&#xff0c;这里不再进行labelme安装及标注的赘述。…

MAC如何在根目录创建文件

在这之前先明确一下啥是根目录。 打开终端&#xff0c;输入cd /&#xff0c;然后输入 ls 查看根目录下有哪些文件 可以看到 usr、etc、opt 这些文件的地方才叫根目录&#xff0c;而不是以用户命名&#xff0c;可以看到音乐、应用程序、影片、桌面的地方哈 介绍一种叫做软连接…

C++算法:数据流的中位数

题目 中位数是有序整数列表中的中间值。如果列表的大小是偶数&#xff0c;则没有中间值&#xff0c;中位数是两个中间值的平均值。 例如 arr [2,3,4] 的中位数是 3 。 例如 arr [2,3] 的中位数是 (2 3) / 2 2.5 。 实现 MedianFinder 类: MedianFinder() 初始化 MedianFin…

数据预处理—滑动窗口采样数据

一个简单的例子&#xff1a; # data: 这是要应用滑动窗口采样的输入数据&#xff0c;通常是一个序列&#xff0c;例如列表或NumPy数组。 # window_size: 这是滑动窗口的大小&#xff0c;表示每个窗口中包含的元素数量。 # step_size: 这是滑动窗口移动的步长&#xff0c;表示每…

(※)力扣刷题-栈和队列-用队列实现栈

255.用队列实现栈 使用队列实现栈的下列操作&#xff1a; push(x) – 元素 x 入栈 pop() – 移除栈顶元素 所以后面实现的时候会留下一个元素 top() – 获取栈顶元素 empty() – 返回栈是否为空 注意: 你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, …

2023年中国粘度指数改进剂行业需求现状及前景分析[图]

润滑油添加剂指用于提高润滑油使用性能、耐久性及功效&#xff0c;从而增强机械和发动机使用性能的产品&#xff0c;分为单剂和复合剂两大类产品。单剂产品主要是清净剂、分散剂、抗氧抗腐剂、极压抗磨剂、抗氧剂、增粘剂、防锈剂、降凝剂等具有单一特性的添加剂产品&#xff1…

存储数据保护技术——HyperClone克隆与HyperMirror卷镜像技术介绍

目录 HyperClone克隆 基本概念 克隆的特点 工作原理 注意事项 HyperMirror卷镜像 HyperClone克隆 基本概念 克隆是快照技术的一种&#xff1b;在不中断主机业务的情况下&#xff0c;对源数据在某个时间点的一致性数据副本&#xff0c;数据同完成后成为完整的数据副本 …

一天吃透Java集合面试八股文

内容摘自我的学习网站&#xff1a;topjavaer.cn 常见的集合有哪些&#xff1f; Java集合类主要由两个接口Collection和Map派生出来的&#xff0c;Collection有三个子接口&#xff1a;List、Set、Queue。 Java集合框架图如下&#xff1a; List代表了有序可重复集合&#xff0c…

【C++笔记】模板进阶

【C笔记】模板进阶 一、非类型模板参数二、类模板的特化三、模板的分离编译 一、非类型模板参数 我们之前学过的模板虽然能很好地帮我们实现泛型编程&#xff0c;比如我们可以让一个栈存储int类型的数据&#xff0c;一个栈存储double类型的数据&#xff1a; template <cla…

Git 为文件添加执行权限

背景 当你是一台Linux&#xff0c;想要给文件加权限很简单&#xff0c;只需要执行以下命令 chmod x filename就可以给文件添加执行权限&#xff0c;但是如果你是Windows那就很麻烦了 解决方案 假设这里有一个名为 file.sh 的文件&#xff0c;内容如下&#xff1a; #!/bin/…

视频剪辑SDK,实现高效的移动端视频编辑

为了满足企业对视频编辑的需求&#xff0c;美摄提供了iOS/Android端视频编辑SDK技术开发服务&#xff0c;帮助企业快速高效地制作高质量视频。本文将详细介绍美摄的视频编辑SDK的优势和特点&#xff0c;以及如何为企业提供技术解决方案。 随着智能手机的普及和移动互联网的发展…