LeetCode刷题记录【1】(有序数组合并,移除数组指定元素,删除有序数组中重复项)

自己记录一下刷题内容。

合并有序数组

题目

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

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

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

示例 1:

css 复制代码
输入: 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:

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

示例 3:

ini 复制代码
输入: 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) 的算法解决此问题吗?

法一:Array.prototype.sort()

第一时间就想到了这个,本来以为是一个不太行的方法,结果官方题解第一个就是这个。实在是没想到,原来算法题可以调库的吗???

思路:很简单,就直接将第二个数组塞到nums1里,然后对nums1进行调用sort即可。

代码

js 复制代码
/**
 * @param {number[]} nums1
 * @param {number} m
 * @param {number[]} nums2
 * @param {number} n
 * @return {void} Do not return anything, modify nums1 in-place instead.
 */
 var merge = (nums1, m, nums2, n)=>{
     for(let j = 0; j<n; ++j){
        nums1[m+j] = nums2[j];
     }
     nums1.sort((a, b)=>{
        return a-b;
     });
 }

法二:双指针

刚才的实在是太奇特了,还是得正经做一下。

思路:用指示变量i,j指示数组下标,需要新建一个数组,比较原来两数组中元素的大小,决定将谁的元素插入到新数组中,同时注意移动下标。最后完成后,逐个将新数组的元素赋值给nums1。

代码

js 复制代码
/**
 * @param {number[]} nums1
 * @param {number} m
 * @param {number[]} nums2
 * @param {number} n
 * @return {void} Do not return anything, modify nums1 in-place instead.
 */
var merge = function(nums1, m, nums2, n) {
    let i=0, j=0;
    const temp = [];
    let cur; // 记录选中元素
    while(i<m || j<n){
        // 某一格数组到头了但还都在循环中,需要特殊判断,直接将没到头的那个数组的元素全按下标顺序塞进去即可
        if(i === m){ // nums1到头了
            cur = nums2[j++]; 
        }else if(j === n){ // nums2到头了
            cur = nums1[i++];
        }else if(nums1[i] <= nums2[j]){ // 相等的情况下也是nums1优先进入新数组(满足nums1中元素必须在前面)
            cur = nums1[i++];
        }else{
            cur = nums2[j++];
        }
        temp.push(cur); // 将选中的元素放到新数组中
    }
    for(let r = 0; r<temp.length; ++r){ // 回赋给nums1
        nums1[r] = temp[r];
    }
};

移除元素

题目

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

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

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

说明:

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

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

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

go 复制代码
// nums 是以"引用"方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
    print(nums[i]);
}

示例 1:

ini 复制代码
输入: 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:

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

提示:

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

解法

思路:找到值与输入的相等的元素,然后让它后面的元素依次向前覆盖即可,并更新当前的数组有效长度。

代码

js 复制代码
/**
 * @param {number[]} nums
 * @param {number} val
 * @return {number}
 */
var removeElement = function(nums, val) {
    function doRemove(nums, index, len){ // 定义一下这个函数,依次向前覆盖
        for(let i = index; i<len; ++i){
            if(i+1 !== nums.length){
                nums[i] = nums[i+1];
            }
        }
    }

    let numberOfDelete = 0;
    let i = 0;
    while(i<nums.length-numberOfDelete){
        if(nums[i] === val){
            doRemove(nums, i, nums.length-numberOfDelete);
            ++numberOfDelete;
            --i;
        }
        ++i;
    }

    return nums.length-numberOfDelete;
};

这个解法的时间和空间代价还是挺低的。

删除有序数组中的重复项

题目

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

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k

判题标准:

系统会用下面的代码来测试你的题解:

java 复制代码
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:

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

示例 2:

ini 复制代码
输入: 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 已按 非严格递增 排列

法一:ES6 Set数据结构

思路:ES6新增的Set数据结构是一个类似数组的数据结构,但是其中不会出现重复元素,可以利用这个特性来解题。当然这个方法还是有些奇怪。

代码

js 复制代码
/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    // 直接ES6 
    let temp = new Set(nums);
    temp = Array.from(temp);
    for(let i = 0; i<temp.length; ++i){
        nums[i] = temp[i];
    }
    return temp.length;
};

时间很快但空间很拉跨(很显然空间要拉跨):

法二:双指针

还是得整点正常的解法的。双指针就很不错。

思路 :还是遍历,不过是从下标为1开始遍历,使用一个index记录一下不重复的数量同时当一下新数组的下标指针。需要注意,数组为有序数组,所以如果是重复元素,必然是相邻的,所以可以用nums[i]与nums[i-1]来比较比较,看是不是相同,不相同的话就可以将nums[index]覆盖为nums[i]

代码

js 复制代码
/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    // 双指针 
    if(nums.length === 0){// 防止一个没有
        return 0;
    }
    // 注意:因为是有序数组,所以相同重复元素肯定是相邻的
    let index = 1;
    for(let i = 1; i<nums.length; ++i){ // 从1开始找就行
        if(nums[i] !== nums[i-1]){ // 前面的和后面的不相等,不重复了就
            nums[index] = nums[i]; // 直接覆盖掉即可(要么是自己盖自己,要么是覆盖掉一个重复的)
            ++index; // 唯一元素数量++,并且相当于修改后的数组的下标后移
        }
    }   

    return index;
};

表现比较中庸。

相关推荐
懒大王爱吃狼36 分钟前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
劲夫学编程37 分钟前
leetcode:杨辉三角
算法·leetcode·职场和发展
毕竟秋山澪39 分钟前
孤岛的总面积(Dfs C#
算法·深度优先
浮生如梦_3 小时前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测
励志成为嵌入式工程师5 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
逐·風5 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
捕鲸叉5 小时前
创建线程时传递参数给线程
开发语言·c++·算法
Devil枫5 小时前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试
A charmer5 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
wheeldown6 小时前
【数据结构】选择排序
数据结构·算法·排序算法