算法合集 | 双指针 | Leetcode 27. 移除元素

81 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第17天,点击查看活动详情

前言

本系列文章主要会总结一些常见的算法题目以及算法的易错点,难点,以及一些万用的公式,并且结合实际的 Leetcode 题目来进行加深理解以及实际应用,算法这种东西,属于是一到用时方恨少的类型,在平时总结一些常见的简单算法,经常磨练自己的算法思维,对于日常的开发还是能有不少的帮助的。

  • 今天主要来看一下双指针的一些基础知识和简单题目

什么是双指针

严格的来说,双指针只能说是是算法中的一种技巧。

双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。

双指针可以从不同的方向向中间逼近,即对撞指针,也可以朝着同一个方向遍历,即快慢指针

对撞指针

日常的算法当中比较常见的应该是对撞指针,就是一个指针在头一个指针在尾,两个指针一同向中间移动

let arr = [1,2,3,4,5,6]
let left = 0
let right = arr.length - 1
while(left<right) {
	...
	left++
	right--
}

这属于比较常见的形式,快速排序就是典型的双指针问题。

快慢指针

快慢指针 指的是两个指针从同一侧开始遍历数组,将这两个指针分别定义为快指针(fast)和慢指针(slow),两个指针以不同的策略移动,直到两个指针的值相等(或其他特殊条件)为止,如快指针(fast)每次增长两个,慢指针(slow)每次增长一个。

比如说快慢指针可以用来判断链表是否有环。Leetcode 142. 环形链表 II

Leetcode 27. 移除元素

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

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

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

解题

碰到移除元素,首先想到的就是直接删除数组的元素,js是有提供数组删除某个元素的方法,我们可以从后往前遍历,这样删除数组并不会影响到数组的遍历过程,以此来完成删除

图片.png

但是这样实现不够优雅,需要不断地去改变数组,要注意题目中有一个关键点,就是

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

这样就是告诉我们,这道题其实是需要通过移动数组的元素来实现,我们只需要把相应的几个元素都移动到数组的最后面就好,不必要删除数组元素。

然后利用快慢指针就可以解决上面的问题。

我们可以设定两个指针,一个指针先行的快指针,当快指针碰到目标元素的时候实行跳过,并且慢指针不动,当快指针指向的不是目标元素的时候,慢指针把快指针当前的指向元素作为慢指针指向元素的值,并且根着向下移动,这样我们就可以把数组中不为目标值的元素都移动到数组的前面。

拿 3,2,2,3 来举个例子

图片.png

一开始快指针和慢指针都在第一个元素3 上面,3 并不是目标元素,所以把快指针的值赋值给慢指针,并且向下移动。

图片.png

然后现在快指针和慢指针都指向第二个元素也就是 2 ,这个是目标元素,那么慢指针不动,快指针向下移动。

图片.png

然后快指针在第三个元素的时候也是同理,还是为目标元素,慢指针不动,快指针向下移动。

图片.png

然后在第四个元素时,发现快指针当前的值不是目标元素了,那么就把快指针赋值给慢指针,也就是当前数组的二个元素的位置,然后移动快慢指针,发现快指针已经结束循环了,那么慢指针指向的 第二个元素,就是题目要求的移除目标元素后的数组长度,并且现在的数组变成了 [3,3,2,3] 前两个元素就是题目要求的,移除了所有的 2 以后,剩下的元素。

function removeElement(nums: number[], val: number): number {
    let slownumber = 0
    let fastnumber = 0
    while (fast < nums.length) {
        if (nums[fast] !== val) {
            nums[slow++] = nums[fast];
        }
        fast++;
    }
    return slow;
};

图片.png

图片.png