顺序表和链表的8道算法题

移除元素

题目连接放这了https://leetcode.cn/problems/remove-element/

思路一

创建一个新数组:首先遍历原数组的所有数据,把不等于val的值直接放在新数组里,然后返回新数组的长度。由于这个思路不符合题目的要求,所以我们不采用这个解法,这个思路仅作拓展!!!

int removeElement(int* nums, int numsSize, int val)
{int n1, n2;n1 = n2 = 0;int arr[numsSize];while (n2 < numsSize){if (nums[n2] != val){arr[n1] = nums[n2];n1++;}n2++;}return n1;
}

思路二

使用两个临时变量n1和n2,n2负责遍历数组,n1负责将不等于val的值重新赋值给数组,最后n1就是新数组的下标

这是原数组:

开始进行遍历和赋值操作:

int  removeElement(int* nums, int  numsSize, int  val)
{int n1, n2;
n1 = n2 = 0;while(n2 < numsSize){if(nums[n2] != val){nums[n1] = nums[n2];n1++;}n2++;}return n1;
}

合并两个有序数组

题目连接放这了https://leetcode.cn/problems/merge-sorted-array/

思路

由于数组nums1有足够的空间,所以我们选择将两个合并的数组就直接放在数组nums1中,现在我们要考虑如何存放,由于两个数组是有序的并且是递增的,存放也是要求递增,所以我们要么从两个数组的首元素开始遍历比较进行存放,要么从两个数组的尾元素开始遍历比较进行存放。

如果从首元素开始遍历存放,比较得到最小的元素,存放在nums1的第一个位置进行存放(因为最后得到的数组元素也要递增排列,所以要从nums1的第一个位置开始存放);这时候就有一个问题了,nums1前面几个原先的元素可能就找不到了,我们举个例子:nums1=[1,2,3,0,0,0],nums2=[0],开始比较,nums2的0小于nums1的1,那nums1的第一个元素1就会被0覆盖掉,导致元素丢失,为了避免这个情况,我们就需要保存这个元素,可是我们不知道要几个变量来保存元素,毕竟nums1有多少的元素比nums2大是不确定的,所以这个方法就比较难实现。

因此我们考虑从尾部开始遍历存放,这时候我们需要三个临时变量,两个变量是分别从两个数组的尾元素进行遍历,剩下一个变量是从nums1最后一个空间开始来进行赋值存放元素的操作。

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{int l1, l2, l3;l1 = m - 1;l2 = n - 1;l3 = m + n - 1;while (l1 >= 0 && l2 >= 0){if (nums1[l1] > nums2[l2]){nums1[l3--] = nums1[l1--];}else{nums1[l3--] = nums2[l2--];}}while (l2 >= 0){nums1[l3--] = nums2[l2--];}
}

这里稍微解释一下循环遍历条件,首先第一个循环结束条件肯定是两个下标不能小于0,否则会发生数组的越界访问!!!从这个循环条件出来有两种情况,一是l1<0,二是l2<0,为什么不能是两个同时小于0,因为有一个数组会被最先遍历完,然后就会跳出循环,不可能发生两个数组同时遍历完的!!!
跳出循环后,题目要求把nums2合并到nums1中,所以当l2>=0时,说明nums2是没有遍历完的,我们只需要处理这一个条件即可,不用担心nums1了,因为跳出第一个循环后,如果l2>=0,说明nums1数组已经遍历完了,所以不需要考虑nums1了。

移除链表元素

题目连接:https://leetcode.cn/problems/remove-linked-list-elements/

思路一

遍历原链表,将val的节点就地删除。

typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val)
{if (head == NULL){return head;}ListNode* prev, * pcur;prev = pcur = head;ListNode* next;while (pcur){if (pcur->val == val){next = pcur->next;prev->next = next;pcur = next;}else{prev = pcur;pcur = pcur->next;}}if (head->val == val){return head->next;}return head;
}

这里我们要注意了不用free是因为这时OJ题,如果没有特别说明,我们不需要free,当然你也可以free
还有题目有说可能会出现空链表的情况,这个我们需要单独处理。
在循环中我们是无法删除第一个节点的,所以后面我就用来一个判断来专门处理了一下。

思路二

创建新的链表,将不含val 的节点进行尾插即可。

typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val)
{if (head == NULL){return head;}ListNode* NewHead, * NewTail;NewHead = NewTail = (ListNode*)malloc(sizeof(ListNode));ListNode* ptail = head;while (ptail){if (ptail->val != val){//尾插NewTail->next = ptail;NewTail = NewTail->next;}ptail = ptail->next;}NewTail->next = NULL;ListNode* next = NewHead->next;free(NewHead);return next;
}

这里隆重介绍一下哨兵位,哨兵位就是头结点,它不存放任何有效的数据,就是一个站岗的功能,有了哨兵位,我们就可以直接进行尾插操作,而不是要单独处理新链表尾空的情况,比较方便,题目要求我们放回第一个有效的节点地址,也很简单,直接放回哨兵位的next就可以了。
然后我们还要注意一下如果原链表为空的时候,我们需要单独处理的。

反转链表

题目连接:https://leetcode.cn/problems/reverse-linked-list/

思路一

创建新链表,使用头插操作就可以实现链表的反转。

typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head)
{if (head == NULL){return head;}ListNode* NewHead, * NewTail;NewHead = NewTail = (ListNode*)malloc(sizeof(ListNode));NewTail->next = NULL;//先置为空,便于最后一个节点指向NULLListNode* ptail = head;ListNode* next;while (ptail){next = ptail->next;//保存下一个节点NewTail = NewHead->next;//保存新链表原先的第一个节点NewHead->next = ptail;//头插ptail->next = NewTail;//将新的第一个节点和原先的第一个节点进行连接ptail = next;//继续遍历}next = NewHead->next;free(NewHead);return next;
}

思路二

原链表进行操作,改变每一个节点的指向,如下图所示:

typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head)
{if (head == NULL){return head;}ListNode* l1, * l2;l1 = head;l2 = head->next;l1->next = NULL;//先将第一个节点的指向置为NULLwhile (l2){ListNode* next = l2->next;//保存下一个节点l2->next = l1;l1 = l2;l2 = next;}return l1;
}

合并两个有序的链表

题目链接:https://leetcode.cn/problems/merge-two-sorted-lists/

思路

创建新链表,遍历两个链表的所有的节点,然后尾插到新链表里。

typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{ListNode* NewHead, * NewTail;NewHead = NewTail = (ListNode*)malloc(sizeof(ListNode));NewHead->next = NULL;//处理空链表的情况ListNode* l1, * l2;l1 = list1;l2 = list2;while (l1 && l2){if (l1->val < l2->val){NewTail->next = l1;l1 = l1->next;NewTail = NewTail->next;}else{NewTail->next = l2;l2 = l2->next;NewTail = NewTail->next;}}if (l1){NewTail->next = l1;}if (l2){NewTail->next = l2;}ListNode* next = NewHead->next;free(NewHead);return next;
}

这里我将哨兵位的next置为NULL,是因为如果两个链表都是空的话,就会放回NULL,也就少写了一些判断语句。
当循环走出去后,一定有一个链表还没有走完,所以直接进行该链表与新链表连接即可,不需要一个节点一个节点的插入,因为剩下的链表本来就是有序的~~

链表的中间节点

题目连接:https://leetcode.cn/problems/middle-of-the-linked-list/

思路

快慢指针,定义两个指针,一个快指针每次走两步,一个慢指针每次走一步,最后快指针遍历完链表的所有节点之后,慢指针就是链表的中间节点
原理就是:2slow = fast

讨论一下循环结束的条件,当有奇数个节点时:

很显然fast->next==NULL时要跳出循环。

当有偶数个节点时:

当fast==NULL时跳出循环。

现在思考是写while(fast->next && fast) 还是写 while(fast && fast->next),还是两个都可以?

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

公布答案,只能写while(fast && fast->next),两个顺序不能变换,因为如果fast为NULL时,你先写的fast->next会对空指针进行非法访问!!!

环形链表的约瑟夫问题

题目链接:https://www.nowcoder.com/share/jump/9257752291712999799127

思路

这里我们可以使用循环链表来进行操作,循环链表是指头尾节点是相连的:

有了循环链表之后,我们就可以进行删除节点的操作,最后会剩下一个节点,这个节点的next就是它自己,所以循环结束条件就是这个。
用一个计数器来查看是否要进行删除操作,两个指针进行遍历链表,一个保存上一个节点,一个则往前走,一直到循环结束,所以我在创建循环链表这个函数采用放回尾节点,这样便于一开始我们直接拿到头节点和尾节点,方便后续的操作。

typedef struct ListNode ListNode;
ListNode* BuyNewnode(int x)//创建新节点
{ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));if (newnode == NULL){perror("malloc fail");exit(1);}newnode->val = x;newnode->next = NULL;return newnode;
}ListNode* CreatList(int n)//创建循环链表
{ListNode* head, * tail;head = BuyNewnode(1); //创建第一个节点tail = head;for (int i = 2; i <= n; i++){ListNode* newnode = BuyNewnode(i);tail->next = newnode;tail = tail->next;}tail->next = head;//首尾相连return tail;
}int ysf(int n, int m)
{int count = 1;ListNode* pcur, * prev;//创建循环链表prev = CreatList(n);pcur = prev->next;while (prev != prev->next){if (count == m)//删除节点{prev->next = pcur->next;free(pcur);pcur = prev->next;count = 1;}else{prev = pcur;pcur = pcur->next;count++;}}int ret = prev->val;free(prev);return ret;
}

分割链表

题目链接:https://leetcode.cn/problems/partition-list-lcci/

思路:

我们可以创建两个新链表,一个小链表存放小于x的节点,另一个大链表存放大于或等于x的节点,最后将两个链表合并,放回小链表的头指针即可。

typedef struct ListNode ListNode;
struct ListNode* partition(struct ListNode* head, int x)
{if (head == NULL){return head;}ListNode* LessHead, * LessTail;ListNode* BigHead, * BigTail;//创建哨兵位LessHead = LessTail = (ListNode*)malloc(sizeof(ListNode));BigHead = BigTail = (ListNode*)malloc(sizeof(ListNode));ListNode* ptail = head;while (ptail){if (ptail->val < x){LessTail->next = ptail;LessTail = LessTail->next;}else{BigTail->next = ptail;BigTail = BigTail->next;}ptail = ptail->next;}BigTail->next = NULL;//将大连表的尾节点置为NULLLessTail->next = BigHead->next;return LessHead->next;
}

这里要注意你要将大链表的尾节点置为NULL,因为你不确定大链表的尾节点的next是否还指向其他节点!!!
我这里没有删除哨兵位,如果你想删除也可以。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java 中文官方教程 2022 版(四十九)

原文&#xff1a;docs.oracle.com/javase/tutorial/reallybigindex.html JAXB 示例 原文&#xff1a;docs.oracle.com/javase/tutorial/jaxb/intro/examples.html 以下部分描述如何使用包含在 JAXB RI 捆绑包中的示例应用程序。JAXB RI 捆绑包可从jaxb.java.net获取。下载并安装…

【matlab非线性规划工具箱安装1 SeDuMi 1.3工具箱】

【matlab非线性规划工具箱安装1 SeDuMi 1.3工具箱】 该博客是非线性手眼标定代码中所依赖的matlab工具箱的安装内容&#xff0c;除了进行手眼标定以外&#xff0c;该工具箱还可以用于其他的非线性规划问题 手眼标定传送门&#xff1a; 【从零开始进行高精度手眼标定 eye in …

MySQL知识整理

MySQL知识整理 基础第一讲&#xff1a;基础架构&#xff1a;一条SQL查询语句是如何执行的&#xff1f;架构尽量减少长连接的原因和方案为什么尽量不要依赖查询缓存 索引第四讲&#xff1a;深入浅出索引&#xff08;上&#xff09;第五讲&#xff1a;深入浅出索引&#xff08;下…

react 初学增删改查购物车案例

界面 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>react-购物车案例</title><…

Web3 的社会影响:数字社会的新时代

随着科技的不断进步和创新&#xff0c;人类社会正逐步进入数字化时代的新阶段。Web3 技术作为数字社会的重要组成部分&#xff0c;正在以前所未有的方式重塑着我们的社会生活和交往方式。本文将探讨 Web3 技术对社会的影响&#xff0c;以及它所带来的数字社会的新时代。 1. Web…

redis的三大模式的演化及集群模式思考和总结

redis的三大模式&#xff0c;也是循序渐进。 1、主从复制 比如一开始的读写分离的&#xff0c;主从复制。 一个master&#xff0c;多个slave。 master进行写和 增量同步&#xff0c;slave负责读&#xff0c;和接收增量同步的信息。 这样压力减轻。 2、哨兵模式 这个推出…

代码随想录阅读笔记-回溯【子集II】

题目 给定一个可能包含重复元素的整数数组 nums&#xff0c;返回该数组所有可能的子集&#xff08;幂集&#xff09;。 说明&#xff1a;解集不能包含重复的子集。 示例: 输入: [1,2,2]输出: [ [2], [1], [1,2,2], [2,2], [1,2], [] ] 思路 这道题目和上一道子集的题目区别…

数学基础:矩阵

来自: https://www.shuxuele.com/algebra/matrix-determinant.html 一、矩阵的行列式 二、矩阵简单知识 三、矩阵乘法 四、单位矩阵 五、逆矩阵一&#xff1a;简单2阶矩阵求法 六、逆矩阵二&#xff1a;3、4阶逆矩阵求法 6.1 求余子式矩阵 6.2 求代数余子式矩阵 6.3 求伴随矩阵…

快速解锁3D Web渲染引擎HOOPS Communicator轻量化技术

在当今数字化时代&#xff0c;三维模型的使用已经成为许多行业中不可或缺的一部分。然而&#xff0c;随着模型复杂性的增加和数据量的膨胀&#xff0c;如何在Web浏览器中高效加载和渲染这些模型成为了一个挑战。慧都3D Web渲染引擎HOOPS Communicator通过其先进的轻量化技术&am…

泰坦尼克号幸存者预测

泰坦尼克号幸存者预测 1、特征工程概述2、数据预处理3、特征选择与提取4、建模与预测 1、特征工程概述 在上篇 泰坦尼克号幸存者数据分析 中&#xff0c;我们对泰坦尼克号的幸存者做了数据分析&#xff0c;通过性别、年龄、船舱等级等不同维度对幸存者进行了分类统计&#xff0…

FME学习之旅---day24

我们付出一些成本&#xff0c;时间的或者其他&#xff0c;最终总能收获一些什么。 高级地理数据库 教程&#xff1a;地理数据库转换 上述教程包括 如何使用 Esri 模板地理数据库 该内容在FME学习之旅day19 已经学习过 使用地理数据库属性域&#xff1a;编写编码属性域 属…

CSS3 常用样式

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 ✍CSS3 常用样式&#x1f48e;1 CSS3 新增选择器&#x1f339;1.1 属性选择器…

Centos 下载地址

下载镜像地址&#xff1a; 1、官网地址&#xff1a;The CentOS Project 2、阿里镜像站&#xff1a;centos安装包下载_开源镜像站-阿里云 3、清华镜像源&#xff1a;Index of /centos/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 3.、CentOS搜狐镜像&#xff1…

Aritest+python+Jenkins解放双手iOS/Android自动化

ARITest、Python 和 Jenkins 可以结合在一起创建一个自动化测试解决方案&#xff0c;实现持续集成和持续测试的目标。以下是三者如何协同工作的基本概念&#xff1a; 1. **ARITest**&#xff1a; ARITest 是一款功能全面的自动化测试工具&#xff0c;提供 UI 自动化、接口自…

KVM + GFS 分布式存储

目录 一、案例分析 1.1、案例概述 1.2、案例前置知识点 1&#xff09;Glusterfs 简介 2&#xff09;Glusterfs 特点 1.3、案例环境 1&#xff09;案例环境 2&#xff09;案例需求 3&#xff09;案例实现思路 二、案例实施 2.1、安装部署 KVM 虚拟化平台 1&…

OpenHarmony实战:瑞芯微RK3568移植案例

本文章是基于瑞芯微RK3568芯片的DAYU200开发板&#xff0c;进行标准系统相关功能的移植&#xff0c;主要包括产品配置添加&#xff0c;内核启动、升级&#xff0c;音频ADM化&#xff0c;Camera&#xff0c;TP&#xff0c;LCD&#xff0c;WIFI&#xff0c;BT&#xff0c;vibrato…

34. UE5 RPG实现鼠标点击移动

在前面&#xff0c;我们实现过使用键盘按键wasd去实现控制角色的移动&#xff0c;现在&#xff0c;我们实现了InputAction按键触发&#xff0c;后面&#xff0c;实现一下通过鼠标点击地面实现角色移动。 我们将实现两种效果的切换&#xff0c;如果你点击地面快速松开&#xff0…

时间序列分析 # 平稳性检验和ARMA模型的识别与定阶 #R语言

掌握单位根检验的原理并能解读结果&#xff1b;掌握利用序列的自相关图和偏自相关图识别模型并进行初步定阶。 原始数据在文末&#xff01;&#xff01;&#xff01; 练习1、根据某1971年9月-1993年6月澳大利亚季度常住人口变动&#xff08;单位&#xff1a;千人&#xff09;的…

SpringCloud的使用以及五大核心组件

一、SpringCloud介绍 微服务架构的提出者&#xff1a;马丁福勒 https://martinfowler.com/articles/microservices.html // 微服务架构的提出者&#xff1a;马丁福勒&#xff08;中午网&#xff09; http://blog.cuicc.com/blog/2015/07/22/microservices/ 马丁.福勒对微服务…

Linux中磁盘的分区,格式化,挂载和文件系统的修复

一.分区工具 1.分区工具介绍 fdisk 2t及以下分区 推荐 (分完区不保存不生效&#xff0c;有反悔的可能) gdisk 全支持 推荐 parted 全支持 不推荐 ( 即时生效&#xff0c;分完立即生效) 2.fdisk 分区,查看磁盘 格式:fdisk -l [磁盘设备] fdisk -l 查看…