首页 > 其他分享 >移除元素 -- 力扣第27题 -- 暴力、双指针解法

移除元素 -- 力扣第27题 -- 暴力、双指针解法

时间:2024-04-07 19:00:51浏览次数:28  
标签:27 val nums -- 元素 int 数组 移除 指针

题目

https://leetcode.cn/problems/remove-element/description/

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

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

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

示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。

示例 2: 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。

你不需要考虑数组中超出新长度后面的元素。

思路

有的同学可能说了,多余的元素,删掉不就得了。

要知道数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。

暴力解法

这个题目暴力的解法就是两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组。

删除过程如下:

很明显暴力解法的时间复杂度是O(n^2),这道题目暴力解法在leetcode上是可以过的。

代码如下:(C++)

// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int size = nums.size();
        for (int i = 0; i < size; i++) {
            if (nums[i] == val) { // 发现需要移除的元素,就将数组集体向前移动一位
                for (int j = i + 1; j < size; j++) {
                    nums[j - 1] = nums[j];
                }
                i--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
                size--; // 此时数组的大小-1
            }
        }
        return size;

    }
};
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)

双指针法

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

定义快慢指针

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

很多同学这道题目做的很懵,就是不理解 快慢指针究竟都是什么含义,所以一定要明确含义,后面的思路就更容易理解了。

删除过程如下:

很多同学不了解

双指针法(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组、链表、字符串等操作的面试题,都使用双指针法。

后续都会一一介绍到,本题代码如下:(C++)

// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
            if (val != nums[fastIndex]) {
                nums[slowIndex++] = nums[fastIndex];
            }
        }
        return slowIndex;
    }
};

注意这些实现方法并没有改变元素的相对位置!

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

 代码如下:(C++)

/**
* 相向双指针方法,基于元素顺序可以改变的题目描述改变了元素相对位置,确保了移动最少元素
* 时间复杂度:O(n)
* 空间复杂度:O(1)
*/
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int leftIndex = 0;
        int rightIndex = nums.size() - 1;
        while (leftIndex <= rightIndex) {
            // 找左边等于val的元素
            while (leftIndex <= rightIndex && nums[leftIndex] != val){
                ++leftIndex;
            }
            // 找右边不等于val的元素
            while (leftIndex <= rightIndex && nums[rightIndex] == val) {
                -- rightIndex;
            }
            // 将右边不等于val的元素覆盖左边等于val的元素
            if (leftIndex < rightIndex) {
                nums[leftIndex++] = nums[rightIndex--];
            }
        }
        return leftIndex;   // leftIndex一定指向了最终数组末尾的下一个元素
    }
};

 其他语言版本

Java:

class Solution {
    public int removeElement(int[] nums, int val) {
        // 快慢指针
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
            if (nums[fastIndex] != val) {
                nums[slowIndex] = nums[fastIndex];
                slowIndex++;
            }
        }
        return slowIndex;
    }
}

//相向双指针法
class Solution {
    public int removeElement(int[] nums, int val) {
        int left = 0;
        int right = nums.length - 1;
        while(right >= 0 && nums[right] == val) right--; //将right移到从右数第一个值不为val的位置
        while(left <= right) {
            if(nums[left] == val) { //left位置的元素需要移除
                //将right位置的元素移到left(覆盖),right位置移除
                nums[left] = nums[right];
                right--;
            }
            left++;
            while(right >= 0 && nums[right] == val) right--;
        }
        return left;
    }
}
// 相向双指针法(版本二)
class Solution {
    public int removeElement(int[] nums, int val) {
        int left = 0;
        int right = nums.length - 1;
        while(left <= right){
            if(nums[left] == val){
                nums[left] = nums[right];
                right--;
            }else {
                // 这里兼容了right指针指向的值与val相等的情况
                left++;
            }
        }
        return left;
    }
}

Python

(版本一)快慢指针法
class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        # 快慢指针
        fast = 0  # 快指针
        slow = 0  # 慢指针
        size = len(nums)
        while fast < size:  # 不加等于是因为,a = size 时,nums[a] 会越界
            # slow 用来收集不等于 val 的值,如果 fast 对应值不等于 val,则把它与 slow 替换
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
            fast += 1
        return slow
(版本二)暴力法
class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        i, l = 0, len(nums)
        while i < l:
            if nums[i] == val: # 找到等于目标值的节点
                for j in range(i+1, l): # 移除该元素,并将后面元素向前平移
                    nums[j - 1] = nums[j]
                l -= 1
                i -= 1
            i += 1
        return l

 C

int removeElement(int* nums, int numsSize, int val){
    int slow = 0;
    for(int fast = 0; fast < numsSize; fast++) {
        //若快指针位置的元素不等于要删除的元素
        if(nums[fast] != val) {
            //将其挪到慢指针指向的位置,慢指针+1
            nums[slow++] = nums[fast];
        }
    }
    //最后慢指针的大小就是新的数组的大小
    return slow;
}

标签:27,val,nums,--,元素,int,数组,移除,指针
From: https://blog.csdn.net/lpx666168/article/details/137469484

相关文章

  • HTTP错误代码大全,http网站状态码各代表了什么?
    响应码由三位十进制数字组成,它们出现在由HTTP服务器发送的响应的第一行。响应码分五种类型,由它们的第一位数字表示:1、1xx:信息,请求收到,继续处理2、2xx:成功,行为被成功地接受、理解和采纳3、3xx:重定向,为了完成请求,必须进一步执行的动作4、4xx:客户端错误,请求包含语法错误或者......
  • 继续分享 Ti-FlowChart 可视化组件 0.2.1
    望向窗外月亮很亮,今晚继续分享组件开发状态。目前版本是0.2.1(npminstallti-flowchart)版本发布LOG:1.UI介入对局部的样式进行规范化。2.新增流转线动效,让用户能直观看出流向。3.新增操作界面的缩放能力,方便用户可以直观全景。组件的目标:组件UI色调大气,成品......
  • LeetCode题练习与总结:最后一个单词的长度--58
    一、题目描述给你一个字符串s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中最后一个单词的长度。单词是指仅由字母组成、不包含任何空格字符的最大子字符串。示例1:输入:s="HelloWorld"输出:5解释:最后一个单词是“World”,长度为5。示例2:输入:s="......
  • 个人医疗开支预测项目
     注意:本文引用自专业人工智能社区VenusAI更多AI知识请参考原站([www.aideeplearning.cn])项目背景随着医疗成本的持续上涨,个人医疗开支成为一个重要议题。理解影响医疗费用的多种因素对于医疗保险公司、政府机构以及个人都至关重要。利用数据分析和机器学习技术,我们能够更......
  • 【更新】上市公司-ZF环保补贴、补助数据(2008-2022年)
    01、数据简介环保补贴,又称绿色补贴,是ZF在环保领域实施的一种特定补贴。它主要针对那些在经济主体意识上存在偏差或由于资金私有制而无法有效进行环保投资的企业。环保补贴的目的是解决环保问题,帮助企业改进环保设备和工艺,以减少对环境的损害。环保补助1=绿色补贴*100/营业总......
  • 全国地级市-碳排放绩效原始dofile结果数据(含文献及原始数据)2011-2021年
    地级市-碳排放绩效数据的测算,采用GDP、人类发展指数、CO2排放测算碳排放绩效,基于《中国城市统计年鉴》中的数据,经过线性插值和ARIMA方法填补缺失,跨度2011年至2021年。该数据集详细记录了地级市的总碳排放量,但需注意,2008年以前的常住人口和城市化率数据缺失,1999年以前的总碳排放......
  • 【碳中和】上市公司碳信息披露数据-词频统计(1991-2022年)
    数据来源:上市公司年报时间跨度:1991-2022年数据范围:上市公司数据指标:低碳战略、宣传、方针、理念低碳方针低碳战略低碳宣传低碳理念低排放低碳计划低碳意识降碳计划降碳战略低碳发展零碳战略零碳低碳发展战略零低碳能源碳目标......
  • Python——__init__.py文件
    在Python中,__init__.py文件是一个特殊的文件,常用于将一个普通的文件夹变成一个Python包。这个文件的存在告诉Python解释器,该文件夹应该被视为一个Python包或模块,从而可以导入其中的模块或子包。__init__.py的用途:初始化包:__init__.py文件将一个目录标识为Python包,允许......
  • linux三剑客之流编辑器sed
    sed(streameditor)是Linux和Unix系统中一个非常强大的文本处理工具。它主要用于对文本数据进行过滤和转换。sed可以在不打开文件的情况下,直接对输入流进行操作,并且可以将结果输出到标准输出或文件。基本语法:sed[options]'script'[input[output]]'[options]:sed的命令行......
  • 代码随想录(Day 3)
    今日任务1.移除链表元素2.设计链表3.翻转链表1.移除链表元素LeetCode链接链表经典操作,对于原理不过多解释,主要探讨建立虚拟头结点和不建立虚拟头结点的区别。对于链表操作时,大多数参考书上都给出头结点不需要带数据,这样做是有道理的。因为在链表中,我们涉及到链表的操作......