【数据结构】——顺序表刷题
顺序表练习
前面我们学习了顺序表,下面我们通过几道练习来巩固其知识点。
1、移除数组中指定的元素
题目:
https://leetcode.cn/problems/remove-element/description/
我们分析一下题目的要求:
就是有一个数组,然后我们需要在这个数组上进行删除数值等于val的元素,返回删除后数组的有效元素个数。
其实我们分析这个题目就可以发现,这个题目的要求和我们顺序的要求和贴近,其刚刚好是一个数组,然后要返回的是数组的有效的个数,那么我们的顺序表中,一个成员是要存储的数据的数组,一个是表示当前顺序表有效的元素个数,还有一个是表示当前顺序表的容量。
那么我们这道题是否可以利用这个特性呢?
我们看看解题思路:
首先,我们肯定会想到遍历,然后找数组中和val一样的值,那么我们找到后,要如何进行处理呢?那么我们可以使用我们前面学习到的,删除顺序表指定位置的元素的功能。
删除一个后,那么就要继续往下找,直到找到最后。
那么我们可以写一个查找的函数,在遍历数组的时候就进行查找。然后查找到就进行指定位置删除,但是我们还有个问题就是,我们要将提供的数组,创建到一个顺序表中才可以进行此操作,那么我们可以先遍历数组,然后将这些元素尾插到我们的顺序表中,那么我们就需要一个顺序表。
那么我们可以发现这个方法,需要调用很多次函数,会很麻烦,而且代码量会非常大。
那么我们有没有其他的办法呢?
那么下面就是我们这次重点讲的:双指针法。
这个双指针法,并不是说我们创建两个指针变量,而是我们创建两个整型变量,表示数组的下标,然后其一个下标先往前找,如果当前这个位置的元素和指定的元素不相等,那么我们两个下标都往下走,然后继续走,那么当前面的那个下标找到了和指定数据相等的元素,那么我们就先让走在前面的下标往前走一个位置,然后判断这个位置的元素是否和指定元素相等,如果还是,那么就继续往下走,直到下一个位置的元素和指定的不同,然后再将这个元素覆盖到走的慢的那个下标的位置,然后走得慢的这个下标再往后走。
我们两个下标初始位置都为顺序表的头。
代码如下:
可以看到代码顺利通过了,那么我们再来看看我们这个代码有没有其他可能优化的地方呢,我们可以看到我们的循环体中,无论其nums[src]是否等于val我们都需要对src++,那么我们可以将其提取出来如下:
我们再来分析一下我们上面的写法的时间复杂度,那么我们的函数体内,只有一个循环,没有产生循环的嵌套,然后这个循环受输入的numsSize的影响,那么其时间复杂度为O(n),然后其空间复杂度,我们申请的空间的次数为常数次,那么我们的空间复杂度为O(1)。
2、删除有序数组中的重复项
题目链接:删除有序数组的重复项
https://leetcode.cn/problems/remove-duplicates-from-sorted-array/description/
这个题目和上面的题目有点类似,也是删除数组中的元素啊,不过这个题目是要删除的重复项,就是使得这个数组的每个元素都是单一的。不过其要求的返回值也是最后这个数组的有效元素个数。那么我们是否可以也使用双指针来解决这个问题呢?
我们双指针的思想就是一个指针在前面探路,然后后面一个指针接收信息。
那么我们这道题使用双指针的话,要如何去操作呢?
我们这道题有个关键点就是,我们这个数组是有序的,就是说,我们如果遇到了不同的,那么后面是不会再出现一样的元素了。
我们走在前面的指针,每次移动一位,然后和我们走的慢的这个指针当前位置的元素进行比较,如果一样,那么走得快的指针就继续往下找,直到找到不同的,那么我们那个后面的指针就往前走一步,然后将走得快的指针现在那个位置的元素覆盖到走的慢指针的位置,然后重复上面的操作,直到走的快的指针走到了数组的尾。
下面我们来解题:
我们来分析一下上面代码的时间复杂度和空间复杂度:
首先我们的循环就使用了一层,那么其时间复杂度为O(n),然后其申请空间的次数也是常数次,那么其空间复杂度为O(1)。
3、合并两个有序数组
https://leetcode.cn/problems/merge-sorted-array/description/
题目给了两个有序的数组, 是非递减顺序的数组,然后我们要将其合并到第一个数组中,合并后的数组也是有要求的,也是要为非递减顺序排列的。
那么我们很容易就可以想到下面的解法:
我们先将两个数组直接合并,然后再对数组的元素进行排序。
代码如下:
上面的逻辑上是很好理解的,就是先合并再排序,然后这个函数我们再前面也讲过。
其时间复杂度为O(NlogN),,然后空间复杂度为O(1)。
方法二:双指针法
这个题目的双指针法和前面两个题目的双指针法有点区别,这道题目的双指针法是在两个数组上的,前面的是在一个数组上,那么我们定义两个指针:src1和src2。
我们这道题要实现的是将两个数组为非递减的顺序合并到第一个数组中,但是我们直接将元素移动到第一个数组中,我们会发现个问题,就是我们这样操作,可能会导致数组1的原来的元素被覆盖了。那么我们此时要咋办呢?我们发现从前面开始弄还是很难避免这个问题。那么我们是否可以考虑从后往前呢,就从大的数往小的数排。
我们创建一个指针dest,指向第一个数组的最后一个位置,其实就是m+n的位置,然后我们在用两个指针,一个指向第一个数组的最后一个元素的位置,一个指向第二个数组的最后一个元素的位置。然后比较大小,谁的大,那么就将谁放在dest的位置上,然后dest--,然后那个数组的元素进行了移动,那么其就进行--。
然后循环结束的条件是两个指向数组的指针,其中一个到0的位置后就可以结束了,那么就是其要大于等于0。
然后我们那个数组先到0,那么我们这个数组的元素就已经比较完了,然后我们再将没插入完的数组的元素都移动到第一个数组中去。
如下:
那么我们分析一下上面的时间复杂度,首先就是其有三个循环,不过没有嵌套,所以其时间复杂度为O(n),然后空间复杂度,我们申请的空间数量还是常数的,那么其空间复杂度为O(1)。