【数据结构和算法初阶(C语言)】顺序表+单链表经典例题图文详解(题解大合集,搭配图文演示详解,一次吃饱吃好)

news2024/11/26 4:53:28

目录

 1.移除链表元素

1.1思路1:遍历删除 

1. 2  思路2:尾插法 

2.反转链表 

3.链表的中间节点 

 3.1解题思想及过程

3.2快慢指针思想解题---变式:返回链表的倒数第K个节点 

4.合并两个有序链表

4.1解题思想 1取小的尾插

5.反转链表

6、CM11 链表分割 (比较难)

描述

7.OR36 链表的回文结构

8.相交链表 

9.结语


 1.移除链表元素

1203. 移除链表元素icon-default.png?t=N7T8https://leetcode.cn/problems/remove-linked-list-elements/

 

1.1思路1:遍历删除 

struct ListNode* removeElements(struct ListNode* head, int val) {


if(head==NULL)
{
    return NULL;
}
 struct ListNode* cur = head;
struct ListNode* pre = head;

while(cur->next)
{
    if(cur->val==val)
    {
        //删除
        //如果是头结点
        if(head == cur)
        {
            head = cur->next;
            free(cur);
            cur = head;
            pre = cur;
            
        }
        else
        {
            pre->next = cur->next;
            free(cur);
            cur = pre->next;

        }
    }
    else 
    {
        pre= cur;
        cur = cur->next;
    }
   
}
//处理尾巴
if(cur->val == val)
{
    if(head == cur)
    {
        free(cur);
        return NULL;
    }
    else{
        pre->next = cur ->next;
        free(cur);
    }
}

return head;
}

1. 2  思路2:尾插法 

struct ListNode* removeElements(struct ListNode* head, int val) {


// if(head==NULL)
// {
//     return NULL;
// }
//  struct ListNode* cur = head;
// struct ListNode* pre = head;

// while(cur->next)
// {
//     if(cur->val==val)
//     {
//         //删除
//         //如果是头结点
//         if(head == cur)
//         {
//             head = cur->next;
//             free(cur);
//             cur = head;
//             pre = cur;
            
//         }
//         else
//         {
//             pre->next = cur->next;
//             free(cur);
//             cur = pre->next;

//         }
//     }
//     else 
//     {
//         pre= cur;
//         cur = cur->next;
//     }
   
// }
// //处理尾巴
// if(cur->val == val)
// {
//     if(head == cur)
//     {
//         free(cur);
//         return NULL;
//     }
//     else{
//         pre->next = cur ->next;
//         free(cur);
//     }
// }

// return head;


struct ListNode* cur = head;//用于遍历链表
struct ListNode* newhead = NULL;//创建新的头结点
struct ListNode* tail = NULL;//定义一个尾指针
//开始遍历原先的链表
while(cur)
{
    if(cur->val == val)
    {
        struct ListNode* deal = cur;//记录一下要删除的节点
        cur = cur->next;
        free(deal);
    }
    else 
    {
        if(tail == NULL)//第一次插入
        {
        tail = cur;
        newhead = cur;
        } 
        else 
        {
            tail ->next = cur;
            tail = tail ->next;
        }
        cur = cur->next;
    }
    //单独处理一下尾巴最后一个节点要删除的话,我们的这个尾节点要为空
    if(tail)
    {
        tail->next = NULL;
    }
    
}
return newhead;




}

 

2.反转链表 

206. 反转链表icon-default.png?t=N7T8https://leetcode.cn/problems/reverse-linked-list/ 放在第五讲解

3.链表的中间节点 

. - 力扣(LeetCode). - 备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=N7T8https://leetcode.cn/problems/middle-of-the-linked-list/

 3.1解题思想及过程

这道题最简单的方法就是两次遍历的方法,第一次遍历就可以得到链表的长度,从而求得链表的的中间位置,第二次遍历返回中间节点就好。今天重点讲解一次遍历方法使用快慢指针

偶数长度的链表遍历结束的条件是:快指针指向空

奇数链表长度的遍历结束的条件是:快指针指向的下一个位置为空 

struct ListNode* middleNode(struct ListNode* head) {
    //快慢指针
     struct ListNode*  slow = head;
    struct ListNode*  fast = head;
    if(head == NULL)//传入空指针
    {
        return NULL;
    }
   
   
    while(fast&&fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;

    
    
}

 

3.2快慢指针思想解题---变式:返回链表的倒数第K个节点 

解题思想:快慢指针

快指针先走K步,然后和慢指针一起移动,直到快指针来到尾节点的下一个位置过后,慢指针指向的位置就是我们的倒数第k个节点。

特别注意就是:如果我们传入空链表或者我们的输入的倒数第几个的数据,但是链表没有那么长的时候,应该返回空。 

struct ListNode* FindKthToTail(struct Listnode* plistHead, int k)
{
	//首先判断一下链表为不为空,为空就返回NULL
	if (plistHead == NULL)
	{
		return NULL;
	}
	struct ListNode* slow, * fast;
	slow = fast = plistHead;

	//先让快指针走K步
	while (k--)
	{
		//但是要注意判断如果我们的链表没有K步长,就返回空
		if (fast == NULL)
		{
			return NULL;
		}
		fast = fast->next;
	}
	//然后快慢指针一起走,直到快指针走到空
	while (fast)
	{
		slow = slow->next;
		fast = fast->next;
	}
	return slow;
}

 

4.合并两个有序链表

21. 合并两个有序链表

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

4.1解题思想 1取小的尾插

主要是尾插思想,由于是有序链表,我们就取小的尾差到新的头结点,当一个链表或者两个链表同时走完就结束,将另外一个链表剩下的所有元素尾插到新的链表中然后返回头结点就可以。为了不增加遍历的时间复杂度,还是定义一个尾指针。

 

当有一个链表先走完时:
 

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    
    struct ListNode* head = NULL;//定义一个头指针
    struct ListNode* tail = NULL;//定义一个尾指针
    //先判断传入的链表中1是否有空链表,有就返回另外一个
    if(list1 == NULL)
    {
        return list2;
    }
    if(list2==NULL)

    {
        return list1;
    }
    while(list1 && list2)
    {
        if(list1->val< list2->val)//取小的尾插
        {
            if(tail == NULL)//判断是否是第一次插入
            {
                tail = head = list1;
                list1 = list1->next;
            }
            else
            {
                tail->next= list1;
               
               list1 = list1->next;
                tail = tail->next;
                
            }

        }
        else
        {
            if(tail == NULL)//判断是否是第一次插入
            {
                tail = head = list2;
                list2 = list2->next;
            }
            else
            {
                tail->next= list2;
                tail = tail->next;
               list2 = list2->next;
                
            }
        }
    }
    //出循环有一个链表为空,就要判断一下是哪一个为空,然后将另外一个进行尾插
    if(list1)
    {
        tail->next = list1;
    }
    if(list2)
    {
        tail->next = list2;
    }
    return head;
}

 

5.反转链表

. - 力扣(LeetCode). - 备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=N7T8https://leetcode.cn/problems/reverse-linked-list/ 

 

 解题思想:头插法

 

 

struct ListNode* reverseList(struct ListNode* head) {

//先判断一下传入的链表是否为空
if(head == NULL)
{
    return NULL;
}
    struct ListNode*  newhead = NULL;
    struct ListNode* cur = head;
    struct ListNode*  after=NULL;
    while(cur)
    {
        after = cur->next;
        cur ->next = newhead;
        newhead = cur;
        cur = after;
    }
    return newhead;
}

 

6、CM11 链表分割 (比较难)

描述

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

做题链接

补充带哨兵位的链表

 

首先解题的整体思想:
大于等于X的放置在一个链表,使用尾插的办法为了不改变顺序

小于X的放置在一个链表,也使用尾插的办法。

最后将两个链表链接起来。

这里使用带哨兵位的链表。我们先看一下代码实现,一边走一边说明问题

 

 

 

那么我们应该将大于数据的链表的尾巴置空。 

class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        // write code here

        struct ListNode* lhead ,*ltail;//定义小于X的值存放的链表的头尾节点
        struct ListNode* ghead ,*gtail;//定义大于X的值存放的链表的头尾节点
        //申请哨兵位空间
        lhead = ltail = (  struct ListNode*)malloc(sizeof(  struct ListNode));
        ghead = gtail = (  struct ListNode*)malloc(sizeof(  struct ListNode));
        //开始循环遍历找
        struct ListNode* cur= pHead;
        while(cur)
        {
            if(cur->val <x)
            {
                ltail ->next = cur;
                ltail = ltail ->next;
                cur = cur->next;
            }
            else {
            gtail->next = cur;
            gtail = gtail->next;
            cur = cur->next;
            }
        }
        //链接
        ltail->next = ghead->next;
          gtail->next = NULL; 
        free(ghead);
        struct ListNode* head = lhead;
        head = head ->next;
        free(lhead);
      return head;

        
    }
};

7.OR36 链表的回文结构

题目地址

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。 给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。 测试样例: 1-2-2-1 返回:true



struct ListNode* reverseList(struct ListNode* head) {

	//先判断一下传入的链表是否为空
	if (head == NULL)
	{
		return NULL;
	}
	struct ListNode* newhead = NULL;
	struct ListNode* cur = head;
	struct ListNode* after = NULL;
	while (cur)
	{
		after = cur->next;
		cur->next = newhead;
		newhead = cur;
		cur = after;
	}
	return newhead;
}

struct ListNode* middleNode(struct ListNode* head) {
	//快慢指针
	struct ListNode* slow = head;
	struct ListNode* fast = head;
	if (head == NULL)//传入空指针
	{
		return NULL;
	}


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



}
bool chkPAlindrome(ListNode* head)
{
	struct ListNode* mid = middleNode(head);
	struct LIstNOde* rmid = reverselist(mid);
	while (rmid && head)
	{
		struct ListNode* scur = head;
		if(rmid->val != scur ->val)
		return false;

		rmid = rmid->next;
		
		scur = head->next;
	}
	
}

8.相交链表 

160. 相交链表

 

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {

    struct ListNode * cura = headA,*curb = headB;
    int lena = 1;
    int lenb = 1;
    while(cura->next)
    {
        cura = cura->next;
        lena++;//计算链表a的长度
    }
      while(curb->next)
    {
        curb = curb->next;
        lenb++;//计算链表b的长度
    }
    //如果两个链表相交,那么尾结点的地址一定相等
    //所以这里就可以判断一下两个链表是否相交
    if(cura != curb)
    {
        return NULL;
    }
    int gap = abs(lena-lenb);//计算两个链表之间的差值,用来绝对值
    struct ListNode*longst = headA,*shortlist = headB;
    if(lena<lenb)
    {
        longst = headB;
        shortlist = headA;
    }
    while(gap--)
    {
        longst = longst->next;//长的先走差距步
    }
    //同时找交点
    while(longst != shortlist)
    {
        longst = longst->next;
        shortlist = shortlist->next;
    }
    return longst;
}

 

9.结语

今天关于简单链表的题目解析就更新到这里,下几篇内容是比较复杂的带环链表和复杂连边的题目,大家可以先收藏或者关注一波,方便链接后续新解 

 

 

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

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

相关文章

【工作经验分享】,金三银四大厂面经总结

面试题 一般Android面试分为两部分&#xff1a;Java部分和Android部分&#xff0c;下面说一下自己面试过程遇到的一些具体题目和一些相关知识点。 一 JAVA相关 1&#xff09;JAVA基础 1.java基本数据类型有哪些&#xff0c;int&#xff0c; long占几个字节 2. 和 equals有什…

Maven【5】在IDEA环境中配置和使用Maven

【1】创建父工程 1.创建 Project 按照idea工程的布局&#xff0c;project相当于父工程&#xff0c;里面的module相当于子工程&#xff08;模块工程&#xff09; 我们先来创建最外层这个父工程&#xff1a;

vue在线查看pdf文件

1.引入组件 npm install --save vue-pdf2、pdf组件页面模板 <template><div class"scrollBox" ><el-dialog :visible.sync"open" :top"1" width"50%" append-to-body><div slot"title"><el…

【强化学习的数学原理-赵世钰】课程笔记(七)时序差分方法

一.内容概述 第五节课蒙特卡洛&#xff08;Mento Carlo&#xff09;方法是全课程中第一次介绍 model-free 的方法&#xff0c;本节课的 Temporal-difference learning&#xff08;TD learning&#xff09;是我们要介绍的第二种 model-free 的方法。基于蒙特卡洛&#xff08;Me…

清澈喷嚏,宝宝舒爽轻松:新生儿打喷嚏的温馨指南

引言 新生儿的喷嚏声&#xff0c;如同小鸟啁啾&#xff0c;是宝宝在探索世界时展示的自然表现。尽管这种可爱的行为可能会让家长产生担忧&#xff0c;但实际上&#xff0c;喷嚏是宝宝健康成长的正常体征之一。在这篇文章中&#xff0c;我们将分享一些关于新生儿打喷嚏的注意事…

答题pk小程序源码技术大解析

答题pk小程序源码解析 在数字化时代&#xff0c;小程序因其便捷性、即用性而受到广泛欢迎。其中&#xff0c;答题pk小程序更是成为了一种寓教于乐的现象。它不仅为用户提供了趣味性的知识竞技平台&#xff0c;还为企业、教育机构等提供了互动营销和知识传播的新途径。本文将对…

Minio容器化部署并整合SpringBoot

1、启动minio容器 docker run -p 9000:9000 -p 9090:9090 --name minio -d --restartalways -e MINIO_ACCESS_KEYminio -e MINIO_SECRET_KEYminio -v /usr/local/minio/data:/data -v /usr/local/minio/config:/root/.minio minio/minio server /data --console-addr…

HTML入门:05HTML多媒体

HTML入门&#xff1a;05HTML多媒体 1 video标签1.1 控制按钮&#xff1a;controls1.2 宽度和高度&#xff1a;width和heightt1.3 预载&#xff1a;preload1.4 静音&#xff1a;muted1.5 自动播放&#xff1a;autoplay1.6 无限循环&#xff1a;loop1.7 poster 2 audio标签 在早期…

二百二十七、Linux——通过shell脚本判断HDFS文件是否存在,如果存在则删除HDFS文件

一、目的 在用脚本去实现对HDFS中过期的ODS层原始数据进行删除后&#xff0c;发现还需要在脚本中对HDFS文件是否存在进行判断&#xff0c;否则如果HDFS文件不存在那么任务执行就会报错 报错原因是这一天的HDFS文件并不存在 原有脚本 #! /bin/bash source /etc/profile nowda…

【bug日记】已解决:Invalid bound statement (not found): 找不到对应的Mapper映射类

急着解决问题的哥们直接用目录跳到下文哈 我放传送门了 目录 试错 尝试过确认的东西&#xff1a; 最终解决方案&#xff01;已经完美解决&#xff1a; 只需要在你配置数据源的地方&#xff1a; 更改为&#xff1a; MybatisSqlSessionFactoryBean sessionFactory …

AcWing 1024. 装箱问题

解题思路 相关代码 import java.util.Scanner;public class Main {public static void main(String[] args){Scanner scanner new Scanner(System.in);int v scanner.nextInt();int n scanner.nextInt();int a[] new int[n1];for(int i1;i<n;i) a[i]scanner.nextInt();…

【金九银十】,架构师花费近一年时间整理出来的安卓核心知识

面试经历 主要是根据回忆总结的&#xff08;会有遗漏点&#xff09;。 1. 腾讯&#xff08;QQ音乐&#xff09; 腾讯面试涉及到的范围也很广&#xff0c;甚至问到了C、Kotlin Flutter &#xff0c;也具有一定挑战性的&#xff0c;以下包括腾讯腾讯安卓客户端三面&#xff0c…

k8s-控制器

概述 控制器是什么 控制器是 k8s 内置的管理工具。可以帮助用户实现 Pod 的自动部署、自维护、扩容、滚动更新等功能的自动化程序 为什么要使用控制器 有大量 Pod 需要维护管理需要维护 Pod 的健康状态控制器可以像机器人一样可以替用户完成维护管理的工作 Deployment 控制…

2.14ALU,存储系统

IR存放当下欲执行的指令&#xff1b;PC存放下一条指令的地址&#xff1b; MAR存放欲访问的存储单元地址&#xff1b;MDR存放从存储单元取来的数据&#xff01; 地址译码器是主存的构成部分&#xff0c;不属于CPU&#xff1b;地址寄存器虽然一般属于主存&#xff0c;但是现代计…

如何从 WordPress 中的静态资源中删除查询字符串

今天有一个客户来问询&#xff0c;hostease主机创建的WordPress站点&#xff0c;在GTMetrix或Pingdom进行网站速度测试&#xff0c;看到有关查询字符串的警告。如果不想看到查询字符串的警告&#xff0c;要如何处理呢?我们测试&#xff0c;可以通过一些处理满足这个需求。我们…

瑞数4.0某房地产_瑞数补环境

文章目录 前言目标网站瑞数简介整体流程1.找到cookie的生成位置2.网站分析逆向流程分析补环境 结果结语 前言 本文章中所有内容仅供学习交流&#xff0c;抓包内容、敏感网址、数据接口均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果…

Electron-builder打包安装包——编译篇

突然有一天想打包个桌面程序&#xff0c;没有打包过&#xff0c;经过九牛二虎之力终于打包出来&#xff0c;在此感谢那些热于分享的前辈&#xff01; 本篇只讲打包运行和出现的问题 一、准备工作&#xff1a;提前下载相关资源包&#xff0c;否则在国内环境下可能因为网络问题…

POS 之 验证者队列

前文回顾 ETH网络的权益证明 什么是验证者队列 以太坊的进入和退出队列是等待开始质押或取消质押的验证者。网络对每个 epoch 可以处理的验证器数量有速率限制&#xff08;称为 Churn(流失)&#xff09;。如果尝试进入或退出的验证器数量超过了可处理的数量&#xff0c;那么它…

HTTPS如何保证数据传输的安全性 以及CA签发证书验签

暴力输出&#xff1a; 越看会越深入&#xff0c;睡前难以想通&#xff0c;后深入研究。得之。 有问题 请留言。 ----------追求内心的富足与平和。日行一善。 亓苏姑娘