双指针三大例题

一.移除元素

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

相关推荐
We་ct2 小时前
LeetCode 5. 最长回文子串:DP + 中心扩展
前端·javascript·算法·leetcode·typescript
王老师青少年编程6 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【哈夫曼贪心】:合并果子
c++·算法·贪心·csp·信奥赛·哈夫曼贪心·合并果子
叼烟扛炮6 小时前
C++第二讲:类和对象(上)
数据结构·c++·算法·类和对象·struct·实例化
天疆说6 小时前
【哈密顿力学】深入解读航天器交会最优控制中的Hamilton函数
人工智能·算法·机器学习
wuweijianlove7 小时前
关于算法设计中的代价函数优化与约束求解的技术7
算法
leoufung8 小时前
LeetCode 149: Max Points on a Line - 解题思路详解
算法·leetcode·职场和发展
样例过了就是过了8 小时前
LeetCode热题100 最长公共子序列
c++·算法·leetcode·动态规划
HXDGCL8 小时前
矩形环形导轨:自动化循环线的核心运动单元解析
运维·算法·自动化
谭欣辰8 小时前
C++ 排列组合完整指南
开发语言·c++·算法
代码中介商8 小时前
银行管理系统的业务血肉 —— 流程、状态机、输入校验与持久化(下篇)
c语言·算法