【LeetCode数组#2双指针法】移除元素、删除有序数组中的重复项、移动0
移除元素
给你一个数组 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。
你不需要考虑数组中超出新长度后面的元素
初见思路
输入是一个数组nums和删减目标值val
那么遍历数组我认为是需要的,必须找出待移除的值
然后是如何移除目标值,对于数组来说,里面的值是连续的,所以不能直接就"删除"某个值
实际上我们调用del或者什么方法去删除数组中的值都只是把待删除的值后后面的值覆盖掉了,并没有真正的"删除"数组在该位置的空间,也就是说数组原来的大小是5 ,删除之后其在内存中仍然是5,只是返回的size变成了4
基于此,我们还需要一个循环来覆盖待删除的值
所以,暴力解法需要两层for循环,以下是代码实现
Java版(超时)
class Solution {
public int removeElement(int[] nums, int val) {
int nums_len = nums.length;
for(int i = 0; i < nums.length; i++){
if(nums[i] == val){
for(int j = i + 1; j < nums.length; j++){
nums[j - 1] = nums[j];
}
i -= 1;
nums_len -= 1;
}
}
return nums.length;
}
}
这种方法在java版下是超时的,c++版勉强不超时
可见O(n*n)复杂度的代码在刷题时几乎不可用
常规思路
原地移除元素通常会使用双指针(也叫快慢指针)的方法解决
这里的"双指针"的意思得先说清楚
首先,这个“指针”并不是指C/C++中的那个对象,它只是用来代指数组下标的一个变量,因此在任何语言中你都可以实现双指针,这更多的是一种思想。在应用双指针时,需要考虑好每个指针的意义。
那么,双指针在这里的含义是什么?
这里我们需要一个快指针和一个慢指针
快指针用来在数组中寻找新数组需要的值【其实就是遍历数组】
慢指针则代表着新数组的下标
最开始,快指针和慢指针的位置是一样的(想象一下)
↓(快指针)
[1,2,3,4]
↑(慢指针)
假设现在需要删除的数是3
那么我们需要先遍历数组【注意:我们不是要找待删除的数,而是要找构成新数组的数】,逻辑如下
int slow = 0;
for(int fast = 0; fast < nums.length; i++){
if(nums[fast] != 3){
...//做处理
}
}
return slow;
现在遍历开始
==============step1
↓(快指针),1不需要删
[1,2,3,4]
↑(慢指针) 新数组的值:[1]
==============step2
↓(快指针),2不需要删
[1,2,3,4]
↑(慢指针) 新数组的值:[1,2]
==============step3
↓(快指针),3需要删,慢指针不更新
[1,2,3,4]
↑(慢指针) 新数组的值:[1,2]
==============step4
覆盖
↓(快指针),后面的值覆盖3,4不需要删
[1,2,4, ←4]
↑(慢指针) 新数组的值:[1,2,4]
↓(快指针),遍历结束
[1,2,4,4]
↑(慢指针) 新数组的值:[1,2,4]
以上就是过程,如果觉得抽象建议去搜gif来看
解题模板
代码就按照上面的思路来写就好了
c++版
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
//定义慢指针
int slow = 0;
for(int fast = 0; fast < nums.size(); ++fast){
if(nums[fast] != val){
nums[slow] = nums[fast];
slow++;
}
}
return slow;
}
};
Java版
class Solution {
public int removeElement(int[] nums, int val) {
int slow = 0;//定义慢指针
int nums_len = nums.length;
for(int fast = 0; fast < nums_len; fast++){
if(nums[fast] != val){//遍历并寻找构成新数组可用的数(即除了3以外的),然后添加按新数组下标slow添加到新数组中
nums[slow] = nums[fast];
slow += 1;
}
}
return slow;//此时的slow返回的正好是数组大小(不是从0开始的)
}
}
Python版
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
slow = 0 #慢指针
fast = 0 #快指针
nums_len = len(nums)
while fast < nums_len: #这里不可以用枚举方法,所以不用for来遍历数组,用while代替
if nums[fast] != val:
nums[slow] = nums[fast]
slow += 1
fast += 1
return slow
拓展练习
LeetCode26删除有序数组中的重复项
这题中,快指针仍然是为新数组寻找元素,这些元素的条件是均不相同,判断的方式是在快指针遍历数组的过程中,比较数组相邻两个元素是否相同,不同的即符合要求
慢指针仍为新数组的下标,只有在添加符合要求的数的时候才移动
注意:
- 不要拿慢指针指向的数与快指针指向的数做比较
- 数组中第一个数不用判断,因此快慢指针都从1开始
- 更完美的解法还可以判断一下输入数组的元素是否大于1个
c++版
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int slow = 1;//慢指针初始化为1,第一个数不用比
for(int fast = 1; fast < nums.size(); ++fast){
if(nums[fast - 1] != nums[fast]){//比较相邻两数是否相等
nums[slow] = nums[fast];//新数组(内容是新的,数组还是原来那个数组)只要不重复的值
slow++;
}
}
return slow;
}
};
Java版
class Solution {
public int removeDuplicates(int[] nums) {
int slow = 1;//第一个数不用判断,因此从1开始
for(int fast = 1; fast < nums.length; fast++){
//快指针遍历数组,若相邻两数不同,则将数添加到新数组(新数组下标仍是慢指针)
if(nums[fast - 1] != nums[fast]){
nums[slow] = nums[fast];//此时fast - 1在数值上和slow一致
slow += 1;
}
}
return slow;
}
}
Python版
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
slow = 1
fast = 1
num_len = len(nums)
while fast < num_len:
if nums[fast - 1] != nums[fast]:
nums[slow] = nums[fast]
slow += 1
fast += 1
return slow
LeetCode283移动零
这题也有坑,最开始我按照常规思路做:快指针遇到非0的元素,给通过慢指针加到新数组,然后当前快指针处元素赋值0
c++版
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int slow = 0;
if(nums.size() > 1){
for(int fast = 0; fast < nums.size(); ++fast){
if(nums[fast] != 0){
nums[slow] = nums[fast];
slow++;
}
}
//数组修改完毕,此时需要从slow处开始将将后续元素全部置为0,slow的大小肯定小于数组长度
for(int i = slow; i < nums.size(); ++i) nums[i] = 0;
}
}
};
注意置0代码写的位置
class Solution {
public void moveZeroes(int[] nums) {
int slow = 0;
int nums_len = nums.length;
if(nums_len > 1){
for(int fast = 0; fast < nums_len; fast++){
if(nums[fast] != 0){
nums[slow] = nums[fast];
nums[fast] = 0;
slow += 1;
}
}
}
}
}
这里问题:没有考虑最开始的值是否为0,这导致有部分初始值不为0的用例无法通过【例如[1,0]】
修改:
不在向新数组添加元素后就将fast处元素置0,而是等到fast将数组遍历一遍之后,从slow处开始,将往后的元素全部置0即可
Java版
class Solution {
public void moveZeroes(int[] nums) {
int slow = 0;
int nums_len = nums.length;
if(nums_len > 1){
for(int fast = 0; fast < nums_len; fast++){
if(nums[fast] != 0){
nums[slow] = nums[fast];
slow += 1;
}
}
for(int i = slow; i< nums_len; i++){
nums[i] = 0;
}
}
}
}
Python版(超时)
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
slow = 0
fast = 0
num_len = len(nums)
while fast < num_len:
if nums[fast] != 0:
nums[slow] = nums[fast]
slow += 1
fast += 1
while slow < num_len:
nums[slow] = 0
【LeetCode数组#2双指针法】移除元素、删除有序数组中的重复项、移动0的更多相关文章
- LeetCode 83. Remove Duplicates from Sorted List (从有序链表中去除重复项)
Given a sorted linked list, delete all duplicates such that each element appear only once. For examp ...
- [LeetCode] 82. Remove Duplicates from Sorted List II 移除有序链表中的重复项 II
Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numb ...
- [LeetCode] Remove Duplicates from Sorted List 移除有序链表中的重复项
Given a sorted linked list, delete all duplicates such that each element appear only once. For examp ...
- [LeetCode] Remove Duplicates from Sorted List II 移除有序链表中的重复项之二
Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numb ...
- [LeetCode] 83. Remove Duplicates from Sorted List 移除有序链表中的重复项
Given a sorted linked list, delete all duplicates such that each element appear only once. Example 1 ...
- [LeetCode] 82. Remove Duplicates from Sorted List II 移除有序链表中的重复项之二
Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numb ...
- LeetCode Remove Duplicates from Sorted List 删除有序链表中的重复结点
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode ...
- leetcode83,删除有序链表中的重复元素
Given a sorted linked list, delete all duplicates such that each element appear only once. For examp ...
- 82. Remove Duplicates from Sorted List II(删除有序链表中的重复元素)
Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numb ...
- LeetCode(26): 删除排序数组中的重复项
Easy! 题目描述: 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间 ...
随机推荐
- [转帖]linux系统目录结构介绍
linux的目录结构 Linux系统各个目录的作用 /: 根目录.有且只有一个根目录.所有的东西都是从根目录开始.举个例子:当你在终端里输入"/home",你其实是在告诉服务器,先 ...
- [转帖]Elasticsearch-sql 用SQL查询Elasticsearch
https://www.cnblogs.com/kangoroo/p/7273493.html https://www.cnblogs.com/kangoroo/p/7273493.html Elas ...
- K8S 使用loki 监控 应用日志的搭建办法
1. 背景 这几天一直在用k8s部署分SU的测试环境,开发反馈看日志比较麻烦. 昨天晚上在家里本来想搭建ELK 发现比较重, 又说有一个比较轻量级的 loki 可以实现使用grafana进行监控和查看 ...
- 仅杀掉当前目录的java进程的办法
比较简单,比如当前目录名字是 /su 就可以写成如下: 利用 /proc/ 下面的cwd 来进行判断直接杀进程 尽量路径唯一标识符 进行处理. for i in `ps -ef |grep java ...
- 《SAIS Supervising and Augmenting Intermediate Steps for Document-Level Relation Extraction》论文阅读笔记
代码 原文地址 预备知识: 1.什么是标记索引(token indices)? 标记索引是一种用于表示文本中的单词或符号的数字编码.它们可以帮助计算机理解和处理自然语言.例如,假如有一个字典{ ...
- vue基础系列文章12---创建脚手架
一.交互式命令行创建 1.运行 vue create myvue 选择默认创建模式,会在指定的文件夹下创建文件 2.进入到myvue文件夹,运行:npm run serve 3.访问本地的地址就可以 ...
- PicoPixel贴图查看器
Pico Pixel Pico Pixel是一款纹理查看器,支持查看以下文件格式:TGA,BMP,JPG,DDS,PNG,OpenEXR, KTX, HDR, GIF, TIF. 此外,Pico Pi ...
- 4.3 C++ Boost 日期时间操作库
Boost 库是一个由C/C++语言的开发者创建并更新维护的开源类库,其提供了许多功能强大的程序库和工具,用于开发高质量.可移植.高效的C应用程序.Boost库可以作为标准C库的后备,通常被称为准标准 ...
- Python 提取图片中的GPS信息
JPG图片中默认存在敏感数据,例如位置,相机类型等,可以使用Python脚本提取出来,加以利用,自己手动拍摄一张照片,然后就能解析出这些敏感数据了,对于渗透测试信息搜索有一定帮助,但有些相机默认会抹除 ...
- 网友感到担忧!iOS 17支持第三方应用商店:这下跟安卓没区别了
苹果此前官宣将于6月6日召开WWDC2023大会,按照往年的惯例,在这次大会上将会推出下一代iOS系统,也就是iOS 17.最近国外有关iOS 17的爆料中提到,迫于欧盟法案压力,iOS 17或将支持 ...