前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >数据结构初步(四)- oj练习-线性表之顺序表

数据结构初步(四)- oj练习-线性表之顺序表

作者头像
怠惰的未禾
发布2023-04-27 21:30:38
3900
发布2023-04-27 21:30:38
举报
文章被收录于专栏:Linux之越战越勇

前言

前面学习了顺序表的相关概念后,让我们来会会这几个题!


1. 移除元素

1.1 题目链接

力扣(LeetCode)链接:移除元素


1.2 题目要求

给你一个数组

nums

和一个值

val

,你需要 原地 移除所有数值等于

val

的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用

O(1)

额外空间并 原地 修改输入数组。

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

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

//

nums

是以“引用”方式传递的。也就是说,不对实参作任何拷贝

int len = removeElement(nums, val)

;

// 在函数里修改输入数组对于调用者是可见的。 // 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。

代码语言:javascript
复制
for (int i = 0; i < len; i++) {
    print(nums[i]);
}

1.3 代码框架

代码语言:javascript
复制
int removeElement(int* nums, int numsSize, int val){
    
}

1.4 思路分析

(1)

给定一个数组

nums

,遇到与

val

的数组元素相等就去掉,不相等就保留,假设

count

是数组

nums

中与

val

相等元素的个数,则修改后的数组前

(numsSize-count)

个位置是存放非

val

的有效位置。

(2)

题目要求空间复杂度是

O(1)

,不能开辟额外的临时数组空间。

(3)

我们可以把题目所给的原数组

nums

当作修改元素后的新数组,两个变量记录数组下标,假设

p1

记录原数组下标,

p2

记录新数组下标;

count

记录原数组中与

val

相等的元素个数。

(4)

开始时

p1、p2

的下标都是

0

,分别对应新旧数组的第一个位置,如果

p1

位置的元素等于

val

p1、p2

均往后后移动一位;否则,就把

p1

位置元素放入

p2

位置处,然后

p1

往后移动一位。直到旧数组被

p1

遍历一遍。

时间复杂度

O(n)

空间复杂度

O(1)

1.5 代码实现

代码语言:javascript
复制
int removeElement(int* nums, int numsSize, int val){
    int p1=0;
    int p2=0;
    int count = 0;//重复的数的个数
    //初始下标p1与p2均为0
    //下标p1遍历整个旧数组,下标p2指向新数组

    while(p1 < numsSize){
        if(nums[p1] != val){
            nums[p2++] = nums[p1++];
        }
        else{
            ++p1;
            ++ccount;
        }
    }
    return numsSize - count;
}

2. 移除元素

2.1 题目链接

力扣(LeetCode)链接:删除有序数组中的重复项


2.2 题目要求

一个 升序排列 的数组

nums

,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。 由于在某些语言中不能改变数组的长度,所以必须将结果放在数组

nums

的第一部分。更规范地说,如果在删除重复项之后有

k

个元素,那么

nums

的前

k

个元素应该保存最终结果。 将最终结果插入

nums

的前

k

个位置后返回

k

。 不要使用额外的空间,你必须在 原地 修改输入数组 并在使用

O(1)

额外空间的条件下完成。 判题标准:

代码语言:javascript
复制
//系统会用下面的代码来测试你的题解:
int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案
int k = removeDuplicates(nums); // 调用
assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
    assert nums[i] == expectedNums[i];
}

如果所有断言都通过,那么您的题解将被 通过。

示例 1: 输入:

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

已按 升序 排列


2.3 代码框架

代码语言:javascript
复制
int removeDuplicates(int* nums, int numsSize){ 
}

2.4 思路分析

(1)

题目要求对有序数组进行去重处理,并且不开辟额外的临时数组,那么思路是把题目所给的数组

nums

当作去重后的新数组即可。

(2)

使用变量

old

记录原数组的下标,使用变量

new

记录新数组的下标,使用变量

count

记录重复元素的个数;

(3)

原数组中第一个元素我们默认直接放入了新数组的第一个位置,所以我们直接把

old

初始化为1,记录原数组可能存在的第二个元素的下标,

new

初始化为0,记录当前新数组的最后一个元素。

(4)

old

小于

numsSize

时,进行判断: 如果

old

对应元素不等于

new

对应元素,则

new

先记录新数组下一个位置的下标再把

old

位置元素移动到

new

位置,更新

old

为原数组下一个位置的下标。 如果

old

对应元素等于

new

对应元素,说明新数组中已经存在该元素,故跳过该元素,

old

记录原数组数组下一个位置的下标,

new

不变,

count

自增

1

(5)

old

等于

numsSize

时说明去重完毕;

时间复杂度

O(n)

空间复杂度

O(1)

2.5 代码实现

代码语言:javascript
复制
int removeDuplicates(int* nums, int numsSize){
    int old = 1;
    int new = 0;
    int count = 0;
    while(old < numsSize){
        if(nums[old] == nums[new]){
            ++old;
            ++count;
        }
        else{
            nums[++new] = nums[old++];
        }
    }
    return numsSize - count;
}

3. 移除元素

3.1 题目链接

力扣(LeetCode)链接:合并两个有序数组


3.2 题目要求

给你两个按 非递减顺序 排列的整数数组

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
-109 <= nums1[i], nums2[j] <= 109

进阶:你可以设计实现一个时间复杂度为

O(m + n)

的算法解决此问题吗?


3.3 代码框架

代码语言:javascript
复制
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
}

3.4 思路分析

(1)

采用归并排序的思想,对两个数组元素依次进行比较,但是因为比较后的结果要存入第一个数组

nums1

,并且不借助临时数组存放结果,所以我们对这两个数组的比较不能从前往后进行,这样可能会把

nums1

中未排序的数给覆盖掉;应该从后往前倒着对两个数组进行归并排序。

(2)

整型变量

old1

old2

分别记录原数组

nums1

nums2

的下标;

new

记录新数组的下标,实际上其也是记录数组

nums1

,称呼为新旧数组只是为了好区分而已。

(3)

old1

大于等于

0

并且

old2

大于等于

0

,说明可以进行两个数组可以进行比较: 找出

old1

对应原数组元素与

old2

对应原数组元素的较大者,将其移动到

new

对应新数组位置,之后更新对应原数组下标变量

old1

old2

,更新新数组下标变量

new

(4)

old1

小于

0

或者

old2

小于

0

,说明至少有一个数组的元素已经全部移动到了新数组; 如果是原数组

nums2

元素没有全部移动到新数组,就把

nums2

中剩余元素移动到新数组; 如果是原数组

nums1

元素没有全部移动到新数组,就什么也不用做,因为新数组中的元素实际上是直接存入了原数组

nums1

中,当原数组

nums2

全部元素移动完成就可以看成已经结束了。

(4)

时间复杂度

O(m+n)

空间复杂度

1

3.5 代码实现

代码语言:javascript
复制
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
    int old1 = m-1;//旧数组1的下标old1
    int old2 = n-1;//旧数组2的下标old2
    int new = nums1Size-1;//新数组1的下标
    //归并排序思想,但不能从前往后开始排序,而要反过来从后往前排序。因为会覆盖未排序元素。
    //当有一个数组的下标小于0,说明某一个旧数组元素已经全部移动到新数组了,结束循环
    while(old1 >= 0 && old2 >= 0){
        if(nums1[old1] > nums2[old2]){
            nums1[new] = nums1[old1];
            --old1;
            --new;
        }
        else{
            nums1[new] = nums2[old2];
            --old2;
            --new;
        }
    }
    //因为新数组就是旧数组1,只需旧数组2的全部元素移动到新数组就完成了,即只考虑old2
    while(old2 >= 0){
        nums1[new] = nums2[old2];
        --new;
        --old2;
    }
}

结语

本文到这里就结束了,如果有错误之处欢迎批评指正!


本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-09-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 1. 移除元素
    • 1.1 题目链接
      • 1.2 题目要求
        • 1.4 思路分析
          • 1.5 代码实现
          • 2. 移除元素
            • 2.1 题目链接
              • 2.2 题目要求
                • 2.3 代码框架
                  • 2.4 思路分析
                    • 2.5 代码实现
                    • 3. 移除元素
                      • 3.1 题目链接
                        • 3.2 题目要求
                          • 3.3 代码框架
                            • 3.4 思路分析
                              • 3.5 代码实现
                              • 结语
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档