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