一.移除元素

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