【数据结构】顺序表OJ

news2024/9/20 1:00:14

文章目录

  • 0. 前言
  • 1. 移除元素
  • 2. 删除有序数组中的重复项
  • 3. 合并两个有序数组
  • 4. 结语

0. 前言

在上篇博客中,我们使用C语言实现了顺序表。其中我们也对顺序表的接口进行了完整的实现。但是光实现不够,还是需要题目来练习。于是今天我就为大家带来顺序表的三道OJ题。话不多说,我们这就开始。

1. 移除元素

链接:27. 移除元素

描述

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例1

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

示例2

输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。

提示

  • 0 <= nums.length <= 100
  • 0 <= nums[i] <= 50
  • 0 <= val <= 100

思路1

循环遍历nums数组,当碰到val时,将所有元素向前移动,覆盖掉这个下标的值,numsSize–。

注意点:当连续的两个元素都为val时,如果删除了一个元素,后一个元素依然会删除,但是下标已经越过了这个位置,所以需要回退,然后重新判断是否删除该元素。

最后返回numsSize(数组长度)即可。

当数组中元素大多数元素为val时,为时间复杂度最坏情况。

时间复杂度:O(N^2) 空间复杂度:O(1)

image-20221019180736901

但是这种方法时间复杂度太高了,能不能优化到O(N)?看思路2 ↓


思路2

这个思路就很简单了。额外创建一个数组,把不是val的值放入数组中,最后把元素移动到原数组中,返回新数组的长度。

注意点:当数组为空时,需要额外判断。

image-20221019181121485

能否在不降低时间复杂度的情况下,将时间复杂度优化到O(1)?看思路3↓


思路3(精讲)

题目要求使用O(1)的额外空间,原地修改数组,那么我们肯定是尽量降低时间复杂度,并且不额外开辟数组。

所以,我们使用双指针法

以给定两个下标:destsrc分别从0下标开始。

src遍历数组。若src碰到不等于val的值,就将src对应下标的值,放到原数组中dest下标对应的位置。然后dest++,src++。

如果src碰到等于val的值,就将src++,dest不动。

当src = numsSize时,说明数组已经遍历过一遍了,而元素也已经成功移除。

最后返回dest,就是我数组的长度。

时间复杂度:O(N) 空间复杂度:O(1)

image-20221019002328323

image-20221018220117103

2. 删除有序数组中的重复项

链接:26. 删除有序数组中的重复项

描述

给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。

由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。

将最终结果插入 nums 的前 k 个位置后返回 k 。

不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

示例1

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例2

输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

提示

  • 1 <= nums.length <= 3 * 104
  • -104 <= nums[i] <= 104
  • nums 已按 升序 排列

思路

本题依旧是需要原地修改数组,所以我们采用三指针法

说是三指针,其实也就是三个下标。

给定从0开始的下标i、dest,从1开始的下标j。

j用来遍历数组,i则是用来划定重复数字的区域。为什么这么说?接下来我们讲解i和j的分工后,大家就可以理解这个意思。

在数组升序的前提下,j下标在遍历数组时,会遇到两种情况:

(1) 由于第一个数字一定不是重复项,所以j从下标1开始。如果j遇到的数字和下标i所对应的数字相同,那么j++,继续向后走。

// 对应代码段
if (nums[i] == nums[j])
{
	j++;
}

(2) 一旦j碰到的元素和i不相等,那么就将dest下标对应的位置填上i下标的值。并且dest++。重点来了,此时就说明j现在所在位置就是一组重复数的下一个位置。那么此时就让i = j,让i到新的区域内,然后让j++,让j继续走,直到找到新边界。

// 对应代码段
if (nums[i] != nums[j])
{
	nums[dest++] = nums[i];
	i = j;
	j++;	
}

以上两种情况循环进行,直到j == numsSize停止。

但是请注意,对于最后一个数据来说,此时j++的话,那么j就走到了数组后面,最后一个元素没有放置,但是这时我的 i 对应的元素就是最后一个元素,所以需要处理一下:nums[dest++] = nums[i]

最后返回dest,就是不含重复项数组的大小。

时间复杂度:O(N) 空间复杂度:O(1)

image-20221019002228765

image-20221018232523077

3. 合并两个有序数组

链接:88. 合并两个有序数组

描述

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

示例1

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。

示例2

输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并 [1] 和 [] 。
合并结果是 [1] 。

示例3

输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]
解释:需要合并的数组是 [] 和 [1] 。
合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。

提示

  • nums1.length == m + n
  • nums2.length == n
  • 0 <= m, n <= 200
  • 1 <= m + n <= 200
  • -10^9<= nums1[i], nums2[j] <= 10^9

思路1

另外创建一个数组,分别遍历两个数组。比较两个数组对应下标的元素,将较小的数组放入新数组中,直到一个数组元素放置完毕停止。由于数组是有序的,于是将未放置完毕的数组的数据放置到新数组中。最后拷贝到原数组中。

时间复杂度:O(M + N) 空间复杂度:O(M + N)

image-20221019182001990

由于代码过长,再贴一份~

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
    // 额外创建一个数组
    int* newArr = (int*)malloc((m + n) * sizeof(int));
    int start1 = 0, start2 = 0;
    int count = 0;
    while (start1 < m && start2 < n)
    {
        if (nums1[start1] < nums2[start2])
        {
            newArr[count++] = nums1[start1++];
        }
        else
        {
            newArr[count++] = nums2[start2++];
        }
    }
    // 将未放置的数据放入新数组中
    if (start1 == m)
    {
        for ( ; start2 < n; start2++)
        {
            newArr[count++] = nums2[start2];
        }
    }
    else
    {
        for ( ; start1 < m; start1++)
        {
            newArr[count++] = nums1[start1];
        }
    }
    // 拷贝回原数组
    for (int i = 0; i < count; i++)
    {
        nums1[i] = newArr[i];
    }
}

能否在不改变时间复杂度的情况下,将空间复杂度优化到O(1)?看思路2↓


思路2(精讲)

这道题目其实有一个坑,m不是nums1的长度,而是有效数据的长度。n既是nums2的有效数据的长度,也是nums2的长度。nums1的总长度为m + n。

所以我们便可以使用如下方法:

给定end1、end2下标,分别对应着nums1、nums2数组有效数据的末尾位置。给定end下标,为nums1数组的末尾。

首先明确一点,数组是升序的,之后我们的步骤才能正确执行。

如果end1下标对应元素大于end2下标对应元素,则把end1下标对应元素放到end下标处,然后end1- -,end- -;如果end1下标对应元素小于等于end2下标对应元素,则把end2下标对应元素放到end下标处,end2- -,end- -。直到end1或end2中一个值小于0。

如果nums2元素没有放置完毕(end2 >= 0),则将nums2中剩余元素,按照原本顺序依次放入nums1数组;如果nums1数组没有放置完毕,则无需处理,因为这些元素本来就在nums1数组中。

时间复杂度:O(M + N) 空间复杂度:O(1)

image-20221031183037343
image-20221019165725655

4. 结语

到这里,三道题目就讲解完成了。本篇博客也就到此结束了。

如果有兴趣的小伙伴也可以去刷题练练手。毕竟看懂了并不代表会写了,还得多写多练嘛。

下篇博客我会为大家带来链表的相关知识,我们敬请期待~

如果觉得anduin写的还不错的话,还请一键三连!如有错误,还请指正!

我是anduin,一名C语言初学者,我们下期见!

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

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

相关文章

【雷达仿真 | FMCW TDMA-MIMO毫米波雷达信号处理仿真(可修改为DDMA-MIMO)】

本文编辑&#xff1a;调皮哥的小助理 本文引用了CSDN雷达博主XXXiaojie的文章源码&#xff08;https://blog.csdn.net/Xiao_Jie1&#xff09;&#xff0c;加以修改和注释&#xff0c;全面地、详细地阐述了FMCW TDM-MIMO毫米波雷达的工作原理&#xff0c;同时配套MATLA仿真实现方…

kubernetes

目录 一、容器云发展及主要内容 1、云平台计算,交付标准&#xff08;iaas-----openstack&#xff09; 2、平台即服务(PAAS&#xff09; 3.软件及服务(SAAS) 特点 二、内容 三、kubernetes集群架构与组件 基本组件 (1)Pod&#xff08;最小的资源单位&#xff09; (2)初…

信息系统综合测试与管理__软件测试

一 概念 软件测试是使用人工或者自动手机来运行或测试某个系统的过程&#xff0c; 目的是检测是否满足需求或者比较预期与实际的差别。 软件测试应该覆盖整个开发、维护过程&#xff0c; 不仅仅是编码阶段完成之后进行的一项活动。 常考的软件测试工具为LoadRunner, 是一种…

RHCE——分区、创建逻辑卷

1.创建一个逻辑卷 请按下列要求创建一个新的逻辑卷&#xff1a; 创建一个名为 datastore 的卷组&#xff0c;卷组的大小为4G 逻辑卷的名字为 database ,所属卷组为 datastore,该逻辑卷大小为3G 将新建的逻辑卷格式化为 xfs 文件系统&#xff0c; 2.通过自动挂载将该逻辑卷到/v…

机器学习笔记 十五:随机森林(Random Forest)评估机器学习模型的特征重要性

随机森林1. 随机森林介绍1.1 租赁数据案例2. 特征相关性分析&#xff08;热图&#xff09;2.1 热图绘制2.2 构建随机森林模型2.3 不同特征合并的重要性2.3.1 经纬度合并&#xff08;分3类&#xff09;2.3.2 经纬度合并&#xff08;分2类&#xff09;2.3.3 经纬度合并&#xff0…

HTML CSS游戏官网网页模板 大学生游戏介绍网站毕业设计 DW游戏主题网页模板下载 游戏娱乐网页成品代码...

✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f947; 关于作者: 历任研发工程师&#xff0c;技术组长&#xff0c;教学总监。 十载寒冰&#xff0c;难凉热血&#xff1b;多年过去&#xff0c;历经变迁&#xff0c;物是人非。 然而&#xff0c;对于技术的探索…

系分 - 系统规划

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 系分 - 系统规划 考点摘要 系统规划的步骤&#xff08;★&#xff09;可行性分析&#xff08;★★★&#xff09;成本效益分析&#xff08;★★★&#xff09; 系统规划的步骤 初步调查根据企业战略目标&#…

一行行的代码解密马尔可夫链

使用Python的马尔科夫链实例的实践 一行行的代码解密马尔可夫链。 当我开始学习物理时&#xff0c;我并不喜欢概率的概念。我对用物理学可以对整个世界进行建模的想法非常振奋&#xff0c;不确定性的想法让我很生气:) 事实是&#xff0c;当我们想研究真实的现象时&#xff0c;我…

硬件电路(3)设计篇----为什么栅极型推挽电路不用上P下N?

在做信号控制以及驱动时&#xff0c;为了加快控制速度&#xff0c;经常要使用推挽电路。推挽电路可以由两种结构组成&#xff1a;分别是上P下N&#xff0c;以及上N下P。其原理图如下所示&#xff0c; 在平时中&#xff0c;我个人经常遇到的推挽电路是第一种。当我每次问身边的…

推荐一个不到2MB的C#开发工具箱,集成了上千个常用操作类

今天给大家推荐一个C#开发工具箱&#xff0c;涵盖了所有常用操作类&#xff0c;体积小、功能强大。 项目简介 C# 开发工具箱。大都是静态类&#xff0c;加密解密&#xff0c;反射操作&#xff0c;权重随机筛选算法&#xff0c;分布式短id&#xff0c;表达式树&#xff0c;lin…

单链表简单实现

单链表实现一、为什么会存在单链表&#xff1f;二、什么是单链表&#xff1f;三、单链表结构定义四、单链表的基本操作1、 创建结点2、 销毁链表3、 打印链表4、 尾插节点5、 头插结点6、 尾结点的删除7、 头结点的删除8、 单链表的查找9、 单链表在pos位置之后插入10、单链表在…

在jenkins上创建一个CANoe Job

目录实战项目CANoe 工程配置全局安全创建 slave 节点创建pipline Job&#xff1a; CANoeAutoRun实战项目CANoe 工程 配置全局安全 将代理和SSH Server都设置成随机选取&#xff0c;后面再本机创建slave 节点要用&#xff0c;因为我们会在用一台机器上创建了master和slave节点…

快充伤电池?我来帮何同学做个假设检验

最近看到何同学的视频&#xff0c;拿40部手机花两年半做了关于各种充电的实验视频&#xff0c;视频确实很好看&#xff0c;花里胡哨&#xff0c;看着科技感满满&#xff5e;。但是关于实验设计和根据实验的数据得出最后的结论上似乎有些草率。 实验设计上就不提了&#xff0c;…

周涛:在大数据沙滩上捡拾“珍珠”|奋斗者正青春

“我始终觉得&#xff0c;创新的本原就是好奇心&#xff0c;要像小孩儿一样&#xff0c;一直不断地追问&#xff0c;向这个世界讨要答案。在追寻答案的过程中&#xff0c;要有独立探索和批评的精神&#xff0c;不能轻信权威。” 1 提起电子科技大学教授周涛&#xff0c;大多…

【定语从句练习题】who、which

1. 填空训练 翻译的时候加上 … 的 1.who 2.which 3.which 4.which 5.who 6.which 7.which 8.who 9.who 10.which 11.which 12.who 2. 选择 1.took 2.live 3.she is 3.lost 5.bought 6.is parked 7.it cuts 8.writes 9.make 10.lent you. 10.lend sb. sth 这里需要&…

Java反射06:反射的应用之动态代理

反射的应用之动态代理 &#xff08;这里没听懂&#xff0c;知道反射体现了代理动态性就行&#xff0c;后面框架再学习&#xff09; 代理设计模式的原理 使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原 始对象的调用都要通过代理。代理对象决定是否以及何…

C语言之指针详解

文章目录1 指针1.1 简介1.2 什么是指针1.3 使用指针1.3.1 简单使用1.3.2 NULL 指针1.3.3 指针算术运算1.3.3.1 定义1.3.3.2 遍历数组&#xff1a;递增一个指针1.3.3.3 遍历数组&#xff1a;递减一个指针1.3.3.4 指针的比较1.3.4 指针数组1.3.5 指向数组的指针1.3.6 指向指针的指…

Django中利用Admin后台实现Excel/CSV的导入更新数据库和导出数据到Excel/CSV

本文基于Django自带的admin 后台实现Excel&#xff0c;csv&#xff0c;Json等格式文件的导入并更新后台数据库。 核心是引入 django-import-export模块。 1、测试相数据准备&#xff1a; 我们先创建一个app&#xff1a;app01 python manage.py startapp app01 然后在app01…

软考下午题第1题——数据流,题目分析与案例解析:

答题技巧-【11-12分】分必拿方法&#xff1a; 下午第一题肯定是数据流的题目&#xff0c;那么&#xff0c;数据流肯定要找到对应的实体、关系模式等内容&#xff0c;审题的时候一定要细致&#xff0c;下午时间也是相当够的&#xff0c;所以每句话记住&#xff0c;至少读3遍&am…

【pyhon】利用pygame实现彩图版飞机大战(附源码 可供大作业练习使用)

源码请点赞关注收藏后评论区留言或私信博主 演示视频已上传到我的主页 有需要者可自行观看 演示视频如下&#xff1a; 飞机大战接下来先介绍一下游戏的玩法 在PyCharm中运行《彩图版飞机大战》即可进入如图1所示的游戏界面。 具体的操作步骤如下&#xff1a; &#xff08;1&…