代码随想录-数组-移除元素(双指针)及其相关题目(JS)

文章介绍了几种基于数组的算法问题,包括移除元素、删除排序数组中的重复项和移动零,主要利用双指针法在原地修改数组,保持额外空间复杂度为O(1)。此外,还提到了一个字符串处理问题——比较含退格的字符串,通过逆序遍历判断字符是否被删除。所有问题都提供了相应的代码实现和时间复杂度分析。
摘要由CSDN通过智能技术生成

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

方法

本题特性:数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。

双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

定义快慢指针

  • 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
  • 慢指针:指向更新 新数组下标的位置

代码

/**
 * @param {number[]} nums
 * @param {number} val
 * @return {number}
 */
var removeElement = function(nums, val) {
    var left = 0;
    for (var right = 0;right < nums.length;right++){
        if (nums[right] !== val){
            nums[left] = nums[right];
            left++;
        }
    }
    return left;
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

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 * 10^4
-104 <= nums[i] <= 10^4
nums 已按 升序 排列

方法

同样是两个指针 left 和 right

right指针:寻找新数组的元素,新数组就是不含重复元素

(可以与前面一个元素进行对比【已经保证升序】,也可以与left进行对比)

left指针:指向更新 新数组的下标位置

right 要领先left一个位置

代码

/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    var left = 0;
    // 错开,就相当于right - 1的操作
    for (var right = 1;right < nums.length;right++){
        // nums[right] !== nums[left]同样可以,重点是left放在前面
        // 在大脑中模拟一下
        if (nums[right] !== nums[right - 1]){
            left++;
            nums[left] = nums[right];
        }
    }
    return left + 1;
};

283.移动零

题目

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

示例 1:

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

示例 2:

输入: nums = [0]
输出: [0]

提示:

1 <= nums.length <= 10^4
-2^31 <= nums[i] <= 2^31 - 1

方法

本题方法同移除元素

覆盖掉值为0的所有值,剩下的元素赋值为0

代码

/**
 * @param {number[]} nums
 * @return {void} Do not return anything, modify nums in-place instead.
 */
var moveZeroes = function(nums) {
    let left = 0;
    for (let right = 0;right < nums.length;right++){
        if (nums[right] !== 0){
            nums[left++] = nums[right];
        }
    }
    for (let i = left;i < nums.length;i++){
        nums[i] = 0;
    }
};

844.比较含退格的字符串

题目

给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。

注意:如果对空文本输入退格字符,文本继续为空。

示例 1:

输入:s = "ab#c", t = "ad#c"
输出:true
解释:s 和 t 都会变成 "ac"。

示例 2:

输入:s = "ab##", t = "c#d#"
输出:true
解释:s 和 t 都会变成 ""。

示例 3:

输入:s = "a#c", t = "b"
输出:false
解释:s 会变成 "c",但 t 仍然是 "b"。

提示:

1 <= s.length, t.length <= 200
s 和 t 只含有小写字母以及字符 ‘#’

方法

一个字符是否会被删掉,只取决于该字符后面的退格符,而与该字符前面的退格符无关。因此当我们逆序地遍历字符串,就可以立即确定当前字符是否会被删掉。

具体地,我们定义 skip 表示当前待删除的字符的数量。每次我们遍历到一个字符:

若该字符为退格符,则我们需要多删除一个普通字符,我们让 skip 加 1;

若该字符为普通字符:

若 skip 为 0,则说明当前字符不需要删去;

若 skip 不为 0,则说明当前字符需要删去,我们让 skip 减 1。

这样,我们定义两个指针,分别指向两字符串的末尾。每次我们让两指针逆序地遍历两字符串,直到两字符串能够各自确定一个字符,然后将这两个字符进行比较。重复这一过程直到找到的两个字符不相等,或遍历完字符串为止。

作者:LeetCode-Solution

代码

Java

// 思路巧妙 不考虑空间复杂度,可以尝试一下
class Solution {
    public boolean backspaceCompare(String s, String t) {
        return convert(s).equals(convert(t));
    }

    private String convert(String s) {
        StringBuilder sb = new StringBuilder();
        char[] cs = s.toCharArray();
        int size = 0;
        for (int i = cs.length - 1; i >= 0; i--) {
            if (cs[i] == '#') {
                size++;
            } else if (size == 0) {
                sb.append(cs[i]);
            } else {
                size--;
            }
        }
        return sb.toString();
    }
}

JavaScript

/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var backspaceCompare = function(s, t) {
    return convert(s) == convert(t);
};

var convert = function(str){
    let string = "";
    let size = 0;
    for (let i = str.length - 1;i >= 0;i--){
        if (str[i] == '#'){
            size++;
        } else if (size == 0){
            string += str[i];
        } else {
            size--;
        }
    }
    return string;
}

977.有序数组的平方

题目

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

示例 1:

输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]

示例 2:

输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]

提示:

1 <= nums.length <= 10^4
-10^4 <= nums[i] <= 10^4
nums 已按 非递减顺序 排序

方法

双指针方法

本题包含负数,非递减的排序方式,存在负数的平方大于正数的平方的情况

采用双指针,左右指针分别指向非递减数组两端,平方后比较大小,大的加入新数组(倒序加入),移动大的元素一端的指针,直到left >right。

代码

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var sortedSquares = function(nums) {
    let left = 0,right = nums.length - 1;
    let res = new Array(nums.length).fill(0);
    let n = nums.length - 1;
    while (left <= right){
        if (nums[left] * nums[left] < nums[right] * nums[right]){
            res[n] = nums[right] * nums[right];
            n--;
            right--;
        }else {
            res[n] = nums[left] * nums[left];
            n--;
            left++;
        }
    }
    return res;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值