双指针三大例题

一.移除元素

1.这个题采用双指针解法中最左端和最右端指针

2.在第一次看到这个题目的时候,我只想到了一部分,就是如何返回不等于val元素的个数,我用了一个for循环进行,但后面如何更改数组内的元素我没想明白,题目要求将不等于val的元素排在数组前面,假设有三个不等于val的元素,那么数组前三位必须是它们,它们的顺序无关紧要,并且在它们后面的数也不需要去管。我看了第一个人的题解,他利用是最左边和最右边的数来进行调换,当最左边数等于val,就把最右边数赋值给最左边的,然后下标l++,但我在看完之后有疑问,就是如果这个数组的最左边和最右边的数都是等于val的,那么他的方法明显有漏洞。

3.在我借助工具搜索后,得到了提示,于是我自己写,我想的是依旧用for循环来解决等于val的个数,用while解决数组内容移除问题,我才用的是如果左边元素等于val,进行二次判断右边元素是否等于val,如果等于那么右边下标r--,向左移一位,如果不等于那么右边元素赋值给左边,并且l++,但是我写的是if里面再嵌套了一个if-else(用来判断最右边元素),原理我搞清楚了,表达的很繁琐,最后超出了时间限制,于是我重新进行更改。

4.在这次更改中我发现,不需要去判断最右元素是否等于val,假设现在是相等的,我将右边赋给左边之后,r--,此时最左边元素依旧等于val,但是我们下面还有个else语句,用来说明左边元素不等于val,数组下标怎么变的,如果不等于则l++,此刻等于则不进行l++,下标依旧是0开始,重新循环一次,而右边下标已经向左推移一位,可以进行新的赋值,如此便可解决。

5.在这个重写的过程中,我还有个误区,就是用for循环去返回个数,其实完全不需要,返回l即可,我当时没想明白,为什么不是l+1,因为我觉得是从0开始的,但这意味着,如果数组中没有与val相等的元素,我也要返回个数1吗,这显然不对。

6.最后的问题就是return l的位置,我错误的将return l放在了循环里面,这导致一次循环就会跳出去,逻辑混乱,正确的是放在while循环外面作为方法的返回值。

7.完整代码

class Solution {

public int removeElement(int[] nums, int val) {

int l=0;

int r=nums.length-1;

while(l<=r){

if(nums[l]==val){

nums[l]=nums[r];

r--;

}else{

l++;

}

}

return l;

}

}

二.删除有序数组中的重复项

1.采用的是最左端的前后双指针

2.说实话,第一次看到我没什么思路,我想着依旧是先找出重复元素的个数,因为题目说了大概是有序的,所以我想用第一个元素去和第二个元素比,如果相等,就个数加一,如果不相等那就交换,利用第二个元素去和第三个元素比,但我忽略一个问题就是,重复的元素可以不只有两个,可以是[1,1,1,1,2,3,4,5],所以说我的想法太不实际了。

3.于是我借助了工具来指导我,这题同样是双指针解法,但不同的是,它不是最左和最右两个边缘,而是前后关系。同时第一步,我要先判断这个数组是否为空,如果是空,直接return 0即可,不是的话才可以进行下一步的操作。

4.在这关键的部分,我们首先要设立slow和fast两个坐标,让slow做开头位置=0,fast紧随其后=1,进行循环,如果slow和fast所指的元素不相等,那么slow++,让fast所指元素赋值给slow新位置,如果相等,那么就不用进行这些操作,只需要进行循环的条件步骤,fast++,继续往下寻找新的元素,并且也保证了每个元素都是紧挨着的,还没有重复的,最后的返回个数为slow+1,slow停留在哪里,就代表最后的新元素位置在哪里截止,而又因为是下标,实际个数要加1。

5.完整代码

class Solution {

public int removeDuplicates(int[] nums) {

int slow=0;

int fast=1;

if(nums.length==0){

return 0;

}else{

for(fast=1;fast<nums.length;fast++){

if(nums[slow]!=nums[fast]){

slow++;

nums[slow]=nums[fast];

}

}

}

return slow+1;

}

}

三.合并两个有序数组

1.这题分两种解决办法。一个是暴力解法,采用先合并再冒泡排序,优点是简单易懂,符合逻辑,缺点同样很明显就是时间复杂度很高,效率很慢。另一个同样是用从后往前的双指针来进行优化,下面着重讲解双指针优化法.

2.首先我们看到题目告诉我们nums1和nums2是升序的,nums2需要合并到nums1中,而不是重新生成一个数组,最终的nums1结合了nums2的元素后也要是有序的。

3.既然在合并前两个数组也是升序的,那么我们就可以利用它们各自最大的元素进行比较,大的先放进新的nums1中

我们可以把它想象成两个队伍排队领奖品

nums1 队伍:前 m 个人已经排好(有序),后面 n 个空位

nums2 队伍:n 个人已经排好(有序)

规则:每次让两个队尾的人里,更大的那个去占最后一个空位

class Solution {

public void merge(int[] nums1, int m, int[] nums2, int n) {

int i=m-1;

int j=n-1;

int k=m+n-1;

while(i>=0 && j>=0){

if(nums1[i]>nums2[j]){

nums1[k--]=nums1[i--];

}else{

nums1[k--]=nums2[j--];

}

}

while(j>=0){

nums1[k--]=nums2[j--];//**为什么这里还要再进行一个循环?**因为本身是由nums1为主体,它不需要考虑有没有剩余元素会不会不在数组里面,而如果nums1数组中的元素全部到合适位置了,此刻i会<0,跳出第一个循环,导致nums2中还有元素并没有到nums1中,这个时候我们就需要再进行一次循环,将剩余的元素放在nums1中。

}

}

}

这是完整代码

4.有人会疑问如果出现两个数组有元素相等怎么办,从代码中我们可以看到相等是去else语句那边,也就是会优先将nums2中的元素放进去,那结果会不会乱?会不会不有序?

完全不会!

因为两个数相等,谁先放进去根本不影响最终有序性

举个例子:nums1 = [1,2,3,0,0,0]nums2 = [2,5,6]

当比较到nums1 [i] = 2,nums2 [j] = 2

相等 → 走 else,放 nums2 的 2。结果依然是:1,2,2,3,5,6

相关推荐
灵感__idea2 小时前
Hello 算法:复杂问题的应对策略
前端·javascript·算法
2301_819414303 小时前
C++与区块链智能合约
开发语言·c++·算法
Zaly.3 小时前
【Python刷题】LeetCode 1727 重新排列后的最大子矩阵
算法·leetcode·矩阵
做怪小疯子3 小时前
蚂蚁暑期 319 笔试
算法·职场和发展
计算机安禾3 小时前
【C语言程序设计】第37篇:链表数据结构(一):单向链表的实现
c语言·开发语言·数据结构·c++·算法·链表·蓝桥杯
啊哦呃咦唔鱼3 小时前
LeetCode hot100-73 矩阵置零
算法
阿贵---3 小时前
C++构建缓存加速
开发语言·c++·算法
Queenie_Charlie4 小时前
最长回文子串 V2(Manacher算法)
c++·算法·manacher算法
Evand J4 小时前
【MATLAB复现RRT(快速随机树)算法】用于二维平面上的无人车路径规划与避障,含性能分析与可视化
算法·matlab·平面·无人车·rrt·避障