【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 清理 防火墙已有IP地址的方法
最简单的处理 for i in `firewall-cmd --zone=trusted --list-sources` ;do firewall-cmd --zone=trusted --remov ...
- docker -- images镜像消失问题排查
1. 问题描叙 安装model-serving组件时,错误日志输出push时对应的tag不存在,导致镜像推送失败 2. 问题排查 # 找到对应镜像,尝试手动推送 docker images|grep ...
- 【我在京东做研发】揭秘支撑京东万人规模技术人员协作的行云DevOps平台
分享人:孙长虹 京东云DevOps解决方案架构师 复旦大学计算机系毕业,并拥有人民大学心理学硕士学位.曾任职于Alcatel-Lucent,IBM和惠普,具有丰富的大型复杂产品研发及项目管理经验,擅长 ...
- 动态添加input,然后获取所有的input框中的值
今天遇见一个问题. 点击按钮,动态添加input框(可以添加多个) 然后搜集用户在input中输入的值. 我刚刚在纠结,给input框中注入事件. 但是这样会很麻烦. 经过同事的指点. 我直接去拿v- ...
- 如何减缓vm中慢插入的次数
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 偶然发现vm-storage的监控里有这样一个指标:vm_ ...
- 2024-01-27:用go语言,阿里巴巴走进了装满宝藏的藏宝洞。藏宝洞里面有N堆金币, 第i堆金币的总重量和总价值分别是m[i]、v[i], 阿里巴巴有一个承重量为T的背包,但并不一定有办法将全部的
2024-01-27:用go语言,阿里巴巴走进了装满宝藏的藏宝洞.藏宝洞里面有N堆金币, 第i堆金币的总重量和总价值分别是m[i].v[i], 阿里巴巴有一个承重量为T的背包,但并不一定有办法将全部的 ...
- SqlSugar子查询
1.基础教程 1.1 API目录 *****只查一列***** //First: SqlFunc.Subqueryable<School>().Where(s => s.Id == ...
- 2.5 PE结构:导入表详细解析
导入表(Import Table)是Windows可执行文件中的一部分,它记录了程序所需调用的外部函数(或API)的名称,以及这些函数在哪些动态链接库(DLL)中可以找到.在Win32编程中我们会经常 ...
- Cheat Engine 官方教程汉化
CE修改器官方教程汉化版,区别于前款教程,官方教程中使用的是Tutorial64位程序,如下是经过翻译后的官方文档. 第一步:欢迎 当教程启动时,您应该会看到类似的东西,您只需在阅读帮助文本后单击&q ...
- Tauri VS. Electron - 真实项目的比较
文章翻译自:Tauri VS. Electron - Real world application 以下是正文: 在这篇文章中我将会用真实的项目来比较 Electron 和 Tauri: Authme ...