【蓝桥Java每日一练】————4.移除元素

简介: 今天给大家带来一道基础的双指针题目移除元素

🍋1.移除元素


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


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


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


题目链接:移除元素https://leetcode-cn.com/problems/remove-element/        


            题目解析:首先大家要清楚这里所谓的移除元素,并不是真的移除,我们数组的内存都是连续存储的,是不能单独删除数组中某个元素的,只能进行覆盖。这里之所以要返回新的新数组长度,是它对原数组只遍历到该长度。所以我们的目的就是让值为val的元素全部被后面的元素覆盖掉。


方法1:暴力遍历


           因为目的是要把val全部放到后面,我们可以通过两层for循环,第一层对数组进行遍历,当找到值为val的元素后,我们让val后面的元素全部向前移动一格,这样就将val覆盖掉了。很多人肯定很奇怪,那你这样val不是就没有了?可以答案并不关心你数组尾部的元素是多少,它只会遍历你给的返回值的长度,当然你也可以让val不断和后面元素交换,把它放到后面去,不过那样便是多此一举了。


          时间复杂度O(n^2):n为数组的长度,两层for循环,最坏的情况下会对数组完全遍历两次


          空间复杂度O(1)


class Solution {
    public int removeElement(int[] nums, int val) {
        int n=nums.length;
        //遍历数组
        for(int i=0;i<n;i++){
            //找到了val
            if(nums[i]==val){
                //把val后面的元素全部向前移动一格
                for(int j=i+1;j<n;j++){                
                   nums[j-1]=nums[j];
                }
                //因为后面的元素都向前移动了一格,i也得往左移动一格(仔细想想)        
                i--;
                //删除了一个val,长度当然要减1,这也是我们最后需要返回的答案。
                n--;
            }
        }
        return n;
    }
}


方法2:快慢双指针


            我们定义一个慢指针slowIndex和一个fastIndex,在一个for循环中可以同时完成上面暴力做法的工作。首先两个指针都从数组开始,然后for循环让快指针进行移动,每次移动后判断,快指针的值是否为val,如果不是则将快指针的值覆盖掉慢指针,然后慢指针移动一格。很多人肯定看不懂这个操作的作用,我们的目的既然是主要除了val的其他元素,那我们是不是将除了val的其他元素放到数组前面即可,慢指针的意义代表的是待插入的下标,快指针就是去寻找不为val的元素,理解两个指针的意义再回去看操作大家伙就能明白了。


          时间复杂度O(n):n为数组的长度,只遍历了数组一次        


          空间复杂度O(1)


class Solution {
    public int removeElement(int[] nums, int val) {
        //快慢指针 
        int slowIndex;
        for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
            //不等于val才是我们需要的元素
            if (nums[fastIndex] != val) {
                //把它放到慢指针的位置
                nums[slowIndex] = nums[fastIndex];
                //慢指针移动一格
                slowIndex++;
            }
        }
        //慢指针最后指向的下标就是我们往前放入元素的个数,也就是我们的答案
        return slowIndex;
    }
}

           将朴素做法和双指针做法同时写出来和解析,可以更加让我们感受到双指针的魔力所在,帮助我们更好理解。


相关文章
|
1月前
|
存储 缓存 安全
除了变量,final还能修饰哪些Java元素
在Java中,final关键字不仅可以修饰变量,还可以用于修饰类、方法和参数。修饰类时,该类不能被继承;修饰方法时,方法不能被重写;修饰参数时,参数在方法体内不能被修改。
31 2
|
2月前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
48 3
|
2月前
|
Java
在Java的世界里,Set只接纳独一无二的元素。
【10月更文挑战第16天】在Java的世界里,Set只接纳独一无二的元素。本文通过拟人化的手法,讲述了重复元素从初次尝试加入Set被拒绝,到经历挣扎、反思,最终通过改变自己,成为独特个体并被Set接纳的全过程。示例代码展示了这一过程的技术实现。
26 1
|
1月前
|
Java
那些与Java Set擦肩而过的重复元素,都经历了什么?
在Java的世界里,Set如同一位浪漫而坚定的恋人,只对独一无二的元素情有独钟。重复元素虽屡遭拒绝,但通过反思和成长,最终变得独特,赢得了Set的认可。示例代码展示了这一过程,揭示了成长与独特性的浪漫故事。
22 4
|
1月前
|
存储 Java
判断一个元素是否在 Java 中的 Set 集合中
【10月更文挑战第30天】使用`contains()`方法可以方便快捷地判断一个元素是否在Java中的`Set`集合中,但对于自定义对象,需要注意重写`equals()`方法以确保正确的判断结果,同时根据具体的性能需求选择合适的`Set`实现类。
|
1月前
|
存储 算法 Java
为什么Java Set如此“挑剔”,连重复元素都容不下?
在Java的集合框架中,Set是一个独特的接口,它严格要求元素不重复,适用于需要唯一性约束的场景。Set通过内部数据结构(如哈希表或红黑树)和算法(如哈希值和equals()方法)实现这一特性,自动过滤重复元素,简化处理逻辑。示例代码展示了Set如何自动忽略重复元素。
32 1
|
2月前
|
Java 开发者
在Java集合世界中,Set以其独特的特性脱颖而出,专门应对重复元素
在Java集合世界中,Set以其独特的特性脱颖而出,专门应对重复元素。通过哈希表和红黑树两种模式,Set能够高效地识别并拒绝重复元素的入侵,确保集合的纯净。无论是HashSet还是TreeSet,都能在不同的场景下发挥出色的表现,成为开发者手中的利器。
30 2
|
安全 Java
Day4-如何删除Java集合中的元素(安全与不安全的删除方式详解!)
在删除Java集合中的元素时有会出现安全删除和不安全删除,本案例以list集合为例,list集合的特点:元素有序、可以出现重复的元素。
Day4-如何删除Java集合中的元素(安全与不安全的删除方式详解!)
|
4天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者