初阶数据结构:链表相关题目练习(补充)

目录

  • 1. 单链表相关练习题
    • 1.1 移除链表元素
    • 1.2 反转链表
    • 1.3 链表的中间结点
    • 1.4 链表的倒数第k个结点
    • 1.5 合并两个有序链表
    • 1.6 链表分割
    • 1.7 链表的回文结构
    • 1.8 相交链表
    • 1.9 判断一个链表中是否有环
    • 1.10 寻找环状链表相遇点
    • 1.11 链表的深度拷贝

1. 单链表相关练习题

注:单链表结构上存在一定缺陷,所以链表相关的题目一般都针对与单链表。

1.1 移除链表元素

题目要求:在这里插入图片描述
题目信息:

  1. 头节点head
  2. 移除值val

题目链接:
移除链表元素

方法(顺序处理法):

思路:分析链表结构与结点所处的位置(是否为空链表,结点是否为头结点),分情况依次处理。

过程演示:
在这里插入图片描述

struct ListNode* removeElements4(struct ListNode* head, int val)
{
	struct ListNode* pre = NULL;
	struct ListNode* cur = head;

	while (cur)
	{
		if (cur->val == val)
		{
			//头删
			if (cur == head)
			{
				head = head->next;
				free(cur);
				cur = head;
			}
			else//中间删
			{
				pre->next = cur->next;
				free(cur);
				cur = pre->next;
			}
		}
		else
		{
			pre = cur;
			cur = cur->next;
		}
	}

	return head;
}

1.2 反转链表

题目要求:
在这里插入图片描述
题目链接:
反转链表

过程演示:

struct ListNode* reverseList(struct ListNode* head) 
{
    struct ListNode* pre = NULL;
    struct ListNode* mid = head;
    struct ListNode* cur = NULL;

    if(head)
    {
        cur = head->next;
    }

    while(mid)
    {
        mid->next = pre;
        pre = mid;
        mid = cur;
        if(cur)
        {
            cur = cur->next;
        }
    }

    return pre;
    
}

1.3 链表的中间结点

题目要求:
在这里插入图片描述
题目链接:
链表的中间结点

过程演示(快慢指针法):

struct ListNode* middleNode(struct ListNode* head) 
{
    struct ListNode* fast = head;
    struct ListNode* slow = head;

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

    return slow;
}

1.4 链表的倒数第k个结点

题目要求:
在这里插入图片描述
题目链接:
倒数第k个结点

过程演示:

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) 
{
    struct ListNode* cur = pListHead;
    struct ListNode* pre = pListHead;
    while(cur && k--)
    {
        cur = cur->next;
    }

    if(k > 0)
    {
        pre = NULL;
    }

    while(cur)
    {
        pre = pre->next;
        cur = cur->next;
    }

    return pre;
}

1.5 合并两个有序链表

题目要求:
在这里插入图片描述
题目链接:
合并两个链表

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) 
{
    struct ListNode* newhead = NULL;
    struct ListNode* cur = NULL;
    struct ListNode* newnode = NULL;

    if(list1 == NULL)
        return list2;

    if(list2 == NULL)
        return list1;

    while(list1 != NULL && list2 != NULL)
    {
        if(list1->val <= list2->val)
        {
            newnode = list1;
            list1 = list1->next;
        }
        else
        {
            newnode = list2;
            list2 = list2->next;
        }
        
        if(newhead == NULL)
        {
            newhead = newnode;
            newnode->next = NULL;
            cur = newhead;
        }
        else
        {
            //在遍历过程中,list1 或 list2 会等于 NULL
            cur->next = newnode;
            if(newnode != NULL)
            {
                newnode->next = NULL;
                cur = cur->next;
            }
        }
    }

    //有一个链表本就为空
    if(list1)
    {
        cur->next = list1;
    }

    if(list2)
    {
        cur->next = list2;
    }

    return newhead;
}

1.6 链表分割

题目要求:
在这里插入图片描述
题目链接:
合并两个链表

ListNode* BuyNewNode(int val)
    {
        ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
        newnode->val = val;
        newnode->next = nullptr;

        return newnode;
    }

    ListNode* partition(ListNode* pHead, int x) 
    {
        ListNode* newhead1 = nullptr;
        ListNode* end1 = nullptr;
        ListNode* newhead2 = nullptr;
        ListNode* end2 = nullptr;
        ListNode* cur = pHead;
        while(cur)
        {
            if(cur->val < x)
            {
                if(newhead1 == nullptr)
                {
                    newhead1 = BuyNewNode(cur->val);
                    end1 = newhead1;             
                }
                else 
                {
                    end1->next = BuyNewNode(cur->val);
                    end1 = end1->next;
                }
            }
            else 
            {
                if(newhead2 == nullptr)
                {
                    newhead2 = BuyNewNode(cur->val);
                    end2 = newhead2;             
                }
                else 
                {
                    end2->next = BuyNewNode(cur->val);
                    end2 = end2->next;
                }
            }
            cur = cur->next;
        }

        if(newhead1 == nullptr)
        {
            newhead1 = newhead2;
        }
        else 
        {
            end1->next = newhead2;
        }

        return newhead1;
    }

1.7 链表的回文结构

题目要求:
在这里插入图片描述
题目链接:
回文串

ListNode* reverse(ListNode* head)
    {
        ListNode* pre = nullptr;
        ListNode* mid = head;
        ListNode* cur = head->next;
        while (mid)
        {
            mid->next = pre;
            pre = mid;
            mid = cur;
            if (cur)
            {
                cur = cur->next;
            }
        }

        return pre;
    }

    bool chkPalindrome(ListNode* A)
    {
        //找相同,逆置
        //逐点比较
        //回文结构存在奇数个结点

        //获取中间结点
        ListNode* fast = A;
        ListNode* slow = A;
        while(fast && fast->next)
        {
            fast = fast->next->next;
            if(fast)
            {
                slow = slow->next;
            }
        }

        //表1
        ListNode* newhead2 = slow->next;
        //表2
        slow->next = nullptr;
        ListNode* newhead1 = reverse(A);
        if(fast)
        {
            newhead1 = newhead1->next;
        }


        while (newhead1 && newhead2 && newhead1->val == newhead2->val)
        {
            newhead1 = newhead1->next;
            newhead2 = newhead2->next;
        }

        if (newhead1 == nullptr && newhead2 == nullptr)
        {
            return true;
        }

        return false;
    }

1.8 相交链表

题目要求:
在这里插入图片描述题目链接:
相交链表

void swap(struct ListNode** node1, struct ListNode** node2)
{
    struct ListNode* tmp = *node1;
    *node1 = *node2;
    *node2 = tmp;
}

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{
    struct ListNode* short_list1 = headA;
    struct ListNode* short_list2 = headA;
    struct ListNode* long_list1 = headB;
    struct ListNode* long_list2 = headB;

    while(short_list1 && long_list1)
    {
        short_list1 = short_list1->next;
        long_list1 = long_list1->next;
    }

    if(short_list1)
    {
        swap(&short_list1, &long_list1);
        swap(&short_list2, &long_list2);
    }

    while(long_list1)
    {
        long_list1 = long_list1->next;
        long_list2 = long_list2->next;
    }

    //while((short_list2 && long_list2) || short_list2 != long_list2)
    while(short_list2 && long_list2 && short_list2 != long_list2)
    {
        long_list2 = long_list2->next;
        short_list2 = short_list2->next;
    }

    return short_list2;
}

1.9 判断一个链表中是否有环

题目要求:
在这里插入图片描述
题目链接:
判断是否有环

//逻辑步骤存疑
bool hasCycle(struct ListNode *head) 
{
    struct ListNode* fast = head;
    struct ListNode* slow = head;
	
	//err: while(fast && slow != fast)
    while(fast && fast->next)
    {
        fast = fast->next->next;
        slow = slow->next;
        if(slow == fast)
        {
            return true;
        }
    }

    return false;
}

1.10 寻找环状链表相遇点

题目要求:
在这里插入图片描述
题目链接:
寻找环状链表相遇点

思路依靠结论:一个结点从起始点,一个结点从相遇点(快慢指针相遇点),以同速行走(一次走一步),当他们再一次初次相遇时,此相遇结点即为入环点。

struct ListNode *detectCycle(struct ListNode *head) 
{
    //快慢指针确定首次相遇点
    //起始点与相遇点出发,同速移动,最后的相遇的点即为环的进入点
    struct ListNode* fast = head;
    struct ListNode* slow = head;

    //遍历寻找相遇点
    while(fast && fast->next)
    {
        fast = fast->next->next;
        slow = slow->next;

        if(fast == slow)
        {
            break;
        }
    }
	
	//判断是否为环状链表
    if(fast == NULL || fast->next == NULL)
    {
        return NULL;
    }

    slow = head;
    while(fast != slow)
    {
        fast = fast->next;
        slow = slow->next;
    }

    return fast;
}

1.11 链表的深度拷贝

题目要求:
在这里插入图片描述>题目链接:
链表的深度拷贝

//思路:
//生成拷贝结点
//调整拷贝结点的指针
//还原原链表,链接拷贝结点
struct Node* BuyNewNode(int val)
{
    struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));
    newnode->val = val;
    newnode->next = NULL;
    newnode->random = NULL;

    return newnode;
}

struct Node* copyRandomList(struct Node* head)
{
    struct Node* node1 = head;
	//判断是否为空链表
    if(head == NULL)
    {
        return head;
    }
    //创建新节点
    while (node1)
    {
        struct Node* newnode = BuyNewNode(node1->val);
        newnode->next = node1->next;
        node1->next = newnode;

        node1 = node1->next->next;
    }

    //调整新节点的随机指针
    struct Node* node2 = head->next;
    node1 = head;
    while (node2)
    {
        if (node1->random)
        {
            node2->random = node1->random->next;
        }

        node1 = node1->next->next;
        if (node2->next)
        {
            node2 = node2->next->next;
        }
        else
        {
            node2 = node2->next;
        }
    }

    //还原链表,链接新链表
    node1 = head;
    node2 = head->next;
    struct Node* newhead = head->next;
    while (node1)
    {
        node1->next = node1->next->next;
        if (node2->next)
        {
            node2->next = node2->next->next;
        }

        node1 = node1->next;
        node2 = node2->next;
    }

    return newhead;
}

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

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

相关文章

openai.CLIP多模态模型简介

介绍 OpenAI CLIP&#xff08;Contrastive Language–Image Pretraining&#xff09;是一种由OpenAI开发的多模态学习模型。它能够同时理解图像和文本&#xff0c;并在两者之间建立联系&#xff0c;实现了图像和文本之间的跨模态理解。 如何工作 CLIP模型的工作原理是将来自…

NFS服务器挂载失败问题

问题 mount.nfs: requested NFS version or transport protocol is not supported背景&#xff1a;现在做嵌入式开发&#xff0c;需要在板端挂载服务器&#xff0c;读取服务器文件。挂载中遇到该问题。 挂载命令长这样 mount -t nfs -o nolock (XXX.IP):/mnt/disk1/zixi01.ch…

OpenAI Triton 入门教程

文章目录 Triton 简介背景Triton 与 CUDA 的关系 Triton 开发样例样例一&#xff1a;Triton vector addition 算子Triton kernel 实现kernel 函数封装函数调用性能测试 样例二&#xff1a;融合 Softmax 算子动机Triton kernel 实现kernel 封装单元测试性能测试 样例三&#xff…

Vue3 使用动态组件 component

component 标签&#xff1a;用于动态渲染标签或组件。 语法格式&#xff1a; <component is"标签或组件名">标签内容</component> 动态渲染标签&#xff1a; <template><h3>我是父组件</h3><component is"h1">动态…

蓝桥杯-灌溉

参考了大佬的解题思路&#xff0c;先遍历一次花园&#xff0c;找到所有的水源坐标&#xff0c;把它们存入 “水源坐标清单” 数组内&#xff0c;再读取数组里的水源坐标进行扩散。 #include <iostream> using namespace std; int main() {int n,m,t,r,c,k,ans0,list_i0;…

day04_拦截器Apifox角色管理(登录校验,API接口文档,权限管理说明,角色管理,添加角色,修改角色,删除角色)

文章目录 1. 登录校验1.1 需求说明1.2 实现思路1.3 ThreadLocal1.4 AuthContextUtil1.5 拦截器使用1.5.1 拦截器开发1.5.2 拦截器注册 1.6 代码优化1.6.1 配置优化1.6.2 代码优化1.6.3 前端修改 2. API接口文档2.1 Apifox接口管理平台2.1.1 接口管理平台简介2.1.2 Apifox简介2.…

推荐几款优秀免费开源的导航网站

&#x1f9a9;van-nav 项目地址&#xff1a;van-nav项目介绍&#xff1a;一个轻量导航站&#xff0c;汇总你的所有服务。项目亮点&#xff1a;全平台支持&#xff0c;单文件部署&#xff0c;有配套浏览器插件。效果预览 &#x1f9a9;发现导航 项目地址&#xff1a;nav项目…

Mint_21.3 drawing-area和goocanvas的FB笔记(一)

一、关于freebasic和goocanvas Linux下的FreeBasic是C的一种实现&#xff0c;有指针、类、线程&#xff0c;正则表达式&#xff0c;可内嵌asm和其它语言c等&#xff0c;c的h库几乎都能改写后使用(不能直接用&#xff0c;它的.bi可从h近乎自动转换)&#xff0c;老的Quick Basic…

178文章复现:基于matlab的微震图像去噪

文章复现&#xff1a;基于matlab的微震图像去噪&#xff0c;利用同步压缩连续小波变换进行自动微震去噪和起始检测&#xff0c;SS-CWT 可对时间和频率变化的噪声进行自适应过滤&#xff0c;可以去除小幅值信号中的大部分噪声&#xff0c;检测地震事件并估算地震发生时间。程序已…

浏览器卡顿解决办法 —— DNS设置

1.Windows - 设置 2.网络和Internet 3.以太网 - 更改适配器选项 4.点击你现在用的网络 (WLAN或以太网)&#xff0c;右键属性 5.双击IPv4协议&#xff0c;DNS地址首选114.114.114.114 南京信风网络科技有限公司&#xff0c;成立于2000年&#xff0c;是一家位于中国南京的高…

SpringBoot 自定义注解实现操作日志记录

文章目录 前言正文一、项目结构介绍二、核心类2.1 核心注解2.1.1 CLog 日志注解2.1.2 ProcessorBean 处理器bean 2.2 切面类2.3 自定义线程池2.4 工具类2.4.1 管理者工具类 2.5 测试2.5.1 订单创建处理器2.5.2 订单管理者2.5.3 订单控制器2.5.4 测试报文2.5.5 测试结果 附录1、…

数据结构·栈和队列

1. 栈 1.1 栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一段称为栈顶&#xff0c;另一端称为栈底。 栈中的数据元素遵守 后进先出 LIFO(Last In First Out)的原则&#xff0c;后进来的数…

[linux]进程信号(信号的概念,信号的产生方式,信号的相关接口、指令,函数,信号怎么保存(原理),信号怎么处理)

目录 一、信号的概念 二、信号的产生方式 通过键盘发送信号 通过系统调用&#xff0c;指令 异常 软件条件 三、信号怎么保存&#xff08;原理&#xff09; 信号其他相关常见概念 在内核中表示 sigset_t 四、信号的相关接口、指令&#xff0c;函数 signal sigpr…

数据结构--树的遍历

数据结构--树的遍历 1. 前序中序后序遍历2. 前序中序后序遍历代码 1. 前序中序后序遍历 2. 前序中序后序遍历代码 /** public class TreeNode {int val 0;TreeNode left null;TreeNode right null;public TreeNode(int val) {this.val val;}} */// 前序遍历顺序&#xff1…

SQL函数学习记录

聚合函数 函数是编程语言的基础之一&#xff0c;在对数字的运算中&#xff0c;我们用的最多的就是聚合函数&#xff0c;本篇接下来就详细阐述下SQL中聚合函数的运用。 什么是聚合函数&#xff08;aggregate function&#xff09;&#xff1f; 聚合函数指的是对一组值执行计算…

MYSQL05高级_查看修改存储引擎、InnoDB和MyISAM对比、其他存储引擎介绍

文章目录 ①. 查看、修改存储引擎②. InnoDB和MyISAM对比③. Archive引擎 - 归档④. Blackhole引擎丢数据⑤. CSV - 引擎⑥. Memory引擎 - 内存表⑦. Federated引擎 - 访问远程表⑧. Merge引擎 - 管理多个MyISAM⑨. NDB引擎 - 集群专用 ①. 查看、修改存储引擎 ①. 查看mysql提…

C++ 之LeetCode刷题记录(三十六)

&#x1f604;&#x1f60a;&#x1f606;&#x1f603;&#x1f604;&#x1f60a;&#x1f606;&#x1f603; 开始cpp刷题之旅。 目标&#xff1a;执行用时击败90%以上使用 C 的用户。 16. 最接近的三数之和 给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你…

备战蓝桥杯Day20 - 堆排序的实现

一、每日一题 蓝桥杯真题之互质数的个数 我的解法&#xff1a; 两个数互质&#xff0c;说明两个数的最大公约数是1&#xff0c;定义了一个函数判断两个数的最大公约数&#xff0c;再在循环中判断&#xff0c;并实现计数。可以实现运行&#xff0c;缺点是时间复杂度很高&#…

【Leetcode每日一题】二分查找 - 寻找旋转排序数组中的最小值(难度⭐⭐)(22)

1. 题目解析 Leetcode链接&#xff1a;153. 寻找旋转排序数组中的最小值 这个题目乍一看很长很复杂&#xff0c;又是旋转数组又是最小值的 但是仔细想想&#xff0c;结合题目给的示例&#xff0c;不难看出可以用二分的方法来解决 核心在于找到给定数组里面的最小值 2. 算法原…

预训练大模型LLM的PEFT之—— Prefix Tuning

简介 Prefix Tuning是2021.01提出来的&#xff0c;在它之前&#xff0c;我们使用prompt主要是人工设计模板或者自动化搜索模板&#xff0c;也就是prompt范式的第一阶段&#xff0c;就是在输入上加上prompt文本&#xff0c;再对输出进行映射。这种离散模板对模型的鲁棒性很差。…