注意,移除数组元素并不是简单的删除就可以,因为数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能是覆盖。
说说暴力解法,就两个for循环,第一个for循环遍历数组,寻找需要移除的元素,一旦找到需要移除的元素就进入第二个for循环,第二个for循环就是去除这个需要移除的元素后把后面剩余的元素一个个整体往前移。
这里介绍双指针法来解决移除数组中元素的问题。
双指针法(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组、链表、字符串等操作的面试题,都使用双指针法。
双指针法(快慢指针法):通过一个快指针和一个慢指针在一个for循环下完成两个for循环的工作。
注意,一定要注意快指针和慢指针分别代表什么含义,否则你做的会很懵。
·快指针:寻找新数组的元素,新数组就是不含有目标元素的数组。
·慢指针:指向更新 新数组下标的位置。
代码随想录之双指针法--https://www.bilibili.com/video/BV12A4y1Z7LP
伪代码大致是这样的:val即要删除掉的元素
slow=0;
for(fast=0;fast<nums.size;fast++){
if(nums[fast]!=val){
nums[slow]=nums[fast];
slow++;
}
}
return slow;
让快慢指针都等于0,如果快指针指向的值不等于要删除的元素,则把快指针指向的值赋给慢指针指向的值,然后慢指针++,快指针也继续进入循环++;如果快指针指向的值等于要删除的元素,则慢指针不动,快指针继续循环++。
说一个例子就能很好的理解了。
比如[1,2,3,4,3,5],要删除元素3
首先快慢指针都=0都指向1,
进入循环,快指针指向的1不等于3,所以快指针所指向的值1赋给慢指针所指向的位置,即慢指针指向的值等于1,然后慢指针++,快指针也++;所以新数组有[1]
此时快指针指向的2不等于3,所以快指针所指向的值2赋给慢指针所指向的位置,即慢指针指向的值等于2,然后慢指针++,快指针也++;所以新数组有[1,2]
此时快指针指向的3等于要删除的元素3,所以不进入if,即此时慢指针没有被赋值,然后慢指针这次保持不变,快指针++;所以新数组有[1,2]
此时快指针指向的4不等于3,所以快指针所指向的值4赋给慢指针所指向的位置(慢指针此时指向3),所以此时慢指针所指向的位置的值从3被赋值变成了4,然后慢指针++,快指针也++;所以新数组有[1,2,4]
此时快指针指向的3等于要删除的元素3,所以不进入if,同理慢指针不变,快指针++;所以新数组有[1,2,4]
此时快指针指向的5不等于3,所以快指针所指向的值5赋给慢指针所指向的位置(慢指针此时指向原数组中的4),所以此时慢指针所指向的位置的值从4被赋值变成了5,然后慢指针++,快指针也++(此时fast就=nums.size了所以跳出循环了);所以新数组有[1,2,4,5]
最后慢指针是指向原数组的第二个3那里,下标是4,新的数组长度也是4,所以返回slow即可。
练习题:
①leetcode 27.移除元素
②leetcode 26.删除排序数组中的重复项
为什么时q<num.size()而不是<=呢?难道最后一个就不用比较了?
是这样子的:因为q是从0开始,而num.szie()是从1开始,如12345,q指5位置时q=4而num.size()此时是=5的,所以是<而不是<=
③leetcode 283.移动零
这道题要是不理解,看题解里有个人的动画就一下子就能明白了,这个动画我扣不出来哈哈哈哈哈哈
④leetcode 844.比较含退格的字符串
这道题有两种解决方法,一个是用栈,一个是用双指针
方法一,使用栈,后一个元素影响前一个元素的去留就可以用栈据元素确定栈顶元素的去留
当元素为#时,就弹出栈顶的元素,否则,就加入栈
方法二,使用双指针
一个元素是否被删掉,只取决于该字母后面的#,而与该字母前面的#无关,因此当我们逆序地遍历字符串,就可以立即确定当前字母是否会被删掉。所以让指针分别指向两字符串的末尾。
然后我们还需要定义skip来记录当前#的数量即要删除掉的字母数量,因为有可能出现a###bc。
所以每次我们遍历一个字符:
若该字符为#,则skip++。
若该字符为字母,此时还要分情况,如果当前skip>0即当前字母需要被删除,然后让skip--。
⑤leetcode 977.有序数组的平方
这里要注意一件事,就是原数组是有序的,有负有正,也就是说数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。定义一个和原数组大小的新数组,那么我们可以使用两个指针分别指向原数组的位置0和n-1,每次比较两个指针对应的数,选择较大的那个逆序放进新数组中并且移动对应的指针。
这种方法无需处理某一指针移动至边界的情况。