【算法系列-数组】移除元素 (双指针)

【算法系列-数组】移除元素 (双指针)

1. 算法分析🛸

移除元素这类题的解题思路在于你能否在数组中找到val(这个val有很多种形式,并不是固定的值),并将其按照要求进行移除;

最简单的方法就是通过暴力解决,通过多重循环暴力移除,但这样的代码时间复杂度就会高一些;对此,我们可以使用双指针的方式来解决这类问题:
【题目链接】

定义两个指针:

快指针:用来寻找符合新数组要求的元素

慢指针:用来将旧数组中的元素更新为符合新数组要求的元素

通过循环遍历,让fast指针依次遍历整个旧数组,每找到与val不同的元素(即符合新数组要求),就将这个元素更新到slow指针所在的位置上,然后将slow++,循环结束后slow指针所在位置下标便是整个新数组的数组长度

代码如下

class Solution {
    public int removeElement(int[] nums, int val) {
        int slow = 0;
        for (int fast = 0;fast < nums.length;fast++) {
            if (nums[fast] != val) {
                nums[slow++] = nums[fast];
            }
        }
        return slow;
    }
}

掌握了解题思路后,提供以下几道类型相似的题用来练习:

2. 删除有序数组中的重复性(LeetCode 26)

【题目链接】

2.1 解题思路🎯

双指针

2.2 解题过程🎬

定义两个指针 + 变量val:

快指针:用来寻找未重复出现的元素

慢指针:用来将重复元素更新为未重复出现的元素 val:用来记录最近一次更新的元素 (最开始与数组首元素不一样即可)

通过循环遍历,让fast指针依次遍历整个数组,每找到与val不同的元素,就将这个元素更新到slow指针所在的位置上,然后将slow++,同时更新 val 为 原slow位置更新后的元素,循环重复上述过程,循环结束后slow指针所在位置下标便是整个新数组的数组长度

2.3 代码举例🌰

class Solution {
    public int removeDuplicates(int[] nums) {
        int val = nums[0] + 1;
        int slow = 0;
        for (int fast = 0;fast < nums.length;fast++) {
            if (nums[fast] != val) {
                nums[slow++] = nums[fast];
                val = nums[fast];
            }
        }
        return slow;
    }
}

3. 移动零(LeetCode 283)

【题目链接】

3.1 解题思路🎯

双指针

3.2 解题过程🎬

通过定义两个双指针将非零元素都移动到最前面,之后从slow指针所在位置开始遍历一遍数组将后面的值都赋零即可

3.3 代码举例🌰

class Solution {
    public void moveZeroes(int[] nums) {
        int slow = 0;
        for (int fast = 0;fast < nums.length;fast++) {
            if (nums[fast] != 0) {
                nums[slow++] = nums[fast];
            }
        }
        for (int i = slow;i < nums.length;i++) {
            nums[i] = 0;
        }
    }
}

4. 比较含退格的字符串(LeetCode 844)

【题目链接】

4.1 解题思路🎯

通过双指针 + 设置变量判断 # 是否被消费来进行字符串元素的删减

4.2 解题过程🎬

这次的指针需要从后面开始遍历,因为 # 退格元素是往左删的

设置快慢指针,变量k用来记录当前未被消费的 # 数量 :

  • 当nums[fast]不等于 # 且k = 0时,更新nums[slow] = nums[fast],且slow++;
  • 当nums[fast]不等于 # 且k > 0时,k 减 1,slow位置不变,fast继续向前遍历;
  • 当nums[fast]等于 # 时,k 加 1,slow位置不变,fast继续向前遍历;

遍历完数组后,此时slow + 1 位置开始 即为字符串经过退格后的正确字符串,返回结果后进行判断即可

4.3 代码举例🌰

class Solution {
    public boolean backspaceCompare(String s, String t) {
        String s1 = removeChar(s);
        String t1 = removeChar(t);
        if (s1.equals(t1)) {
            return true;
        }
        return false;
    }

    public String removeChar(String str) {
        String[] nums = str.split("");
        int slow = nums.length -1;
        int k = 0;
        for (int fast = nums.length - 1;fast >= 0;fast--) {
            if (!nums[fast].equals("#")) {
                if (k == 0) {
                    nums[slow--] = nums[fast];
                    continue;
                }
                k--;
            }
            else {
                k++;
            }
            
        }
        StringBuffer ret = new StringBuffer("");
        for (int i = slow + 1;i < nums.length;i++) {
            ret.append(nums[i]);
        }
        return ret.toString();
    }
}

5. 有效数组的平方(LeetCode 977)

【题目链接】

这道题比较特殊,不再是使用快慢指针的方式来解决问题,而是用左右双指针

5.1 解题思路🎯

这道题为我们提供的数组是一个有序的数组,要求我们将数组中的元素平方之后再进行排序返回在这里插入图片描述

很快能想到使用循环 + 库函数的方式就能暴力解决这道题:

class Solution {
    public int[] sortedSquares(int[] nums) {
        for (int i = 0;i < nums.length;i++) {
            nums[i] = nums[i] * nums[i];
        }
        Arrays.sort(nums);
        return nums;
    }
}

但这样带来的时间复杂度为是O(n + nlogn),有没有更高效的方法?可以用双指针✅

在这道题中,我们需要抓住一个关键点

有序数组中元素平方后的最大值一定是由原数组最左边或者最右边的元素的提供的

找到这个关键点后,我们就能通过双指针的方式解决这个问题了

5.2 解题过程🎬

定义左右双指针,并创建一个新的数组ret用来返回结果,定义一个指针cur从新数组的最后开始赋值,进行判断:

  • 当左指针元素的平方值后大于右指针元素的平方值,此时ret[cur] = nums[left] * nums[left],同时left++, cur–
  • 当右指针元素的平方值后大于左指针元素的平方值,此时ret[cur] = nums[right] * nums[right],同时right–, cur–

遍历结束后返回赋值后的新数组即可

5.3 代码举例🌰

class Solution {
    public int[] sortedSquares(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        int[] ret = new int[nums.length];
        int cur = nums.length - 1;
        while (left <= right) {
            int lv = nums[left] * nums[left];
            int rv = nums[right] * nums[right];
            if (lv > rv) {
                ret[cur] = lv;
                left++;
            }
            else {
                ret[cur] = rv;
                right--;
            }
            cur--;
        }
        return ret;
    }
}

以上便是对移除元素类算法的介绍了!!后续还会继续分享其它算法系列内容,如果这些内容对大家有帮助的话请给一个三连关注吧💕( •̀ ω •́ )✧( •̀ ω •́ )✧✨

移除数组中的元素有多种方法可以实现。引用\[1\]中的代码展示了一种方法,通过创建一个新的数组temp来存放不包含指定元素元素。首先遍历原数组,如果元素等于指定元素,则跳过该元素;否则将元素存入temp数组中。最后将temp数组赋值给原数组,即完成了元素移除操作。 另外,引用\[2\]中的代码展示了另一种方法,通过双指针来实现元素移除。定义两个指针i和j,初始时都指向数组的起始位置。遍历数组,如果元素不等于指定元素,则将元素复制到i指针所指向的位置,并将i指针后移一位;否则继续遍历。最后返回i的值,即为移除指定元素后的数组长度。 这两种方法都可以实现移除数组中的元素,具体使用哪种方法取决于实际情况和个人偏好。 #### 引用[.reference_title] - *1* [java数组中删除元素或一个数组元素](https://blog.csdn.net/m0_61466807/article/details/126157280)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [java算法之简单的移除数组中的指定元素Remove Element](https://blog.csdn.net/qq_35559358/article/details/77447473)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Java数组元素的删除](https://blog.csdn.net/wait2023/article/details/121540276)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值