代码随想录算法训练营第一天 LeetCode 704 二分查找、LeetCode 27 移除元素(暴力和双指针)(1)

    return -1;
}

}


因为是左闭右闭的区间,即[L,R]。在while循环中,我们需要考虑的是数组区间一直是合法的。所以,在条件上我们需要思考到底是**left<right**还是**left<=right**。举个例子,区间[1,1]是一个合法区间,表示只有1一个元素,因此在左闭右闭中,left<=right。而在下面给right和left重新赋值的语句,因为已经判定middle大于或小于target,我们可以在新数组中将middle出去,因此赋值应该是middle+1或middle-1。


#### 左闭右开



class Solution {
public int search(int[] nums, int target) {
int left=0;
int right=nums.length;
while (left<right){
int middle = (left+right)/2;
if (nums[middle] > target){
right = middle;
}
else if (nums[middle] < target){
left = middle+1;
}
else {
return middle;
}
}
return -1;
}
}


左闭右开的写法中,需要注意的是right赋值的不同(因为右边取不到所以需要等于nums.length来囊括所有元素)。其次是while循环条件的不同,同样举个例子,[1,1)这个数组是不合法的,因此在左闭右开中left不能等于right。最后是赋值右边界的不同,因为无法取到最右边,因此需要赋值为middle来囊括所有可能元素。而因为左边界可以取到,因此左边界赋值相同。


**低级错误:middle是需要不断改变的,因此要放在循环里。(很低级,大佬轻喷。)**


## LeetCode 27 移除元素


题目链接:[. - 力扣(LeetCode)]( )


首先,我们先思考一下怎么移除数组。数组,是一个**连续**的拥有相同类型的若干元素的集合。既然是连续的,我们无法直接删除某一元素,而是需要将其后面的元素往前覆盖一格来达到删除该元素的效果。而在执行完这一过程后,整个数组大小其实并没有变,只不过不同库函数对返回值进行了包装才达到了大小缩减的效果。(详细见讲解视频前四分钟理论基础:[数组中移除元素并不容易! | LeetCode:27. 移除元素\_哔哩哔哩\_bilibili]( ))


因此,来达成这一效果,可以使用两个for循环或一个for循环(双指针)来解决。


#### 暴力解法


暴力解法也即使用两个for循环来解决问题。像我上面说的,在数组中删除元素相当于将其后面的元素往前覆盖来达成效果。因此实现思路其实很简单,即只要遇到需要删除的元素就把之后的元素往前覆盖并且size-1,直到找不到需要删除的元素为止。



class Solution {
public int removeElement(int[] nums, int val) {
int size = nums.length;
for (int i=0;i<size;i++){
if (nums[i]==val){
for (int j=i+1;j<size;j++){
nums[j-1]=nums[j];
}
i–;
size–;
}
}
return size;
}
}


需要注意的是,在覆盖完后面的元素,即第二个for循环完结后,需要把当前的i-1。原因是因为,我们把后面的元素全部提前覆盖了,因此当前的i位置是它后面的元素,也是我们还没有检查的元素。而如果我们没有对i进行任何操作,那么下一步我们将到i+1的位置,也即是本来i+2位置的元素,而跳过了原本i+1位置的元素没有被检查。因此如果需要删除的元素连续出现就会出现问题。


**而在写上述代码的时候我还犯了一个很低级的错误。我把i--和size--的代码放在了if语句之外,因此出现了空元素的问题。对于i的操作和size减少的操作应该在碰到需要删除的元素时,所以应该在if语句里面。(很低级,大佬轻喷。)**


#### 双指针方法


上述两个for循环的方法的时间复杂度为O(n^2),而我们可以使用双指针,即一个for循环,时间复杂度为O(n)的方法来解决问题。


思路是,分为一个快指针和慢指针。慢指针是需要替换为新元素的位置,快指针是新元素。那么也就是说,我们考虑的是删除元素之外的元素,也就是说重组剩下的元素。例如,一个数组为




|  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- |
| 1 | 2 | 3 | 4 | 3 | 5 |


我们要删除3。那么慢指针和快指针一开始都指向第一个元素,开始替换,即1替换为1,因为1不是需要删除的元素。然后慢指针和快指针都往前移动,继续替换,即2替换为2,因为2也不是需要删除的元素。而当到达3时,快指针将继续移动,因为它代表的是新元素,而慢指针不动,因此快指针到4,然后替换慢指针的位置,即3替换为4。然后,慢指针往前移动,快指针也继续移动,但这时快指针又指向了需要删除的元素3,因此快指针往前移动,而慢指针不动,因此慢指针指向第四个的4,而快指针指向第六个的5。这时,开始替换,即4替换为5。而因为快指针已经走完,这是我们发现慢指针指向的位置其实就是新数组的大小。



class Solution {
public int removeElement(int[] nums, int val) {
int slow=0;
for (int fast=0; fast < nums.length; fast++){
if (nums[fast] != val){

最后的话

最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!

资料预览

给大家整理的视频资料:

给大家整理的电子书资料:

如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!
-1718917002473)]

给大家整理的电子书资料:

[外链图片转存中…(img-iNNJlUdt-1718917002475)]

如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值