本文涉及的LeetCode题目
二分查找:力扣题目链接
移除元素:力扣题目链接
二分查找
关于二分查找,非常简单的一个代码也是非常容易出错的一个代码,重点需要注意各种的边界条件确定不变量和编号量。
可以分为两种选择: 1.[left,right] right部分可以取到,右区间闭合,因此right可以取到。所以while(left<=right),left=right的时候是具有意义的,也是因此我们在right进行初始化的时候right=num.length-1。同时,if(nums[middle]>target)right要赋值为middle-1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是middle-1。
2.[left,right) right部分取不到值,因此while循环的时候while(left<right),同时,right=num.length。并且当if(nums[middle]>target)right要赋值为middle,因为当前这个nums[middle]不一定不是target,那么接下来要查找的左区间结束下标位置就是middle。 之所以不一定不是,因为我们没有取到右区间,所有这里我们需要进行使用middle。
关于具体代码实现,两种实现: right是开口的
class Solution {
public int search(int[] nums, int target) {
///二分法的几种边界条件
//二分法的第二种边界条件左闭右开,所有rigth=mid
//二分法的两种条件都写一下
int left=0,right=nums.length;
//这里right右开和右闭的关系并不一样,如果右闭的话可以取到为了只有一个的情况,我们长度为length-1,取不到的话需要length-1
while(left<right){
int mid=left+(right-left)/2;
if(nums[mid]==target){
return mid;
}
if(nums[mid]>target){
right=mid;
}
if(nums[mid]<target){
left=mid+1;
}
}
return -1;
}
}
right是闭口的
/*
int left=0,right=nums.length-1;
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]==target)
return mid;
if(nums[mid]>target){
right=mid-1;
}
if(nums[mid]<target){
left=mid+1;
}
}
return -1;
下面是我的运行结果:
此外还有一个要注意的点,我们取中间位置,使用mid=left+(right-left)/2,这种方法可以杜绝一些边界值特殊值,如果采用mid=(left+right)/2可能会遇到一些特殊边界情况。
移除元素
给你一个数组nums和一个值val,你需要原地移除所有数值等于val的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用O(1)额外空间并原地修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例1:给定nums=[3,2,2,3],val=3,函数应该返回新的长度2,并且nums中的前两个元素均为2。你不需要考虑数组中超出新长度后面的元素。
示例2:给定nums=[0,1,2,2,3,0,4,2],val=2,函数应该返回新的长度5,并且nums中的前五个元素为0,1,3,0,4.你不需要考虑数组中超出新长度后面的元素。
这道题目的思路和快慢指针一次遍历,时间复杂度O(N),空间复杂度O(1)。快慢指针,通过 快指针来遍历数组的元素,我们判断是否符合情况,通过慢指针来制作相关的返回结果。
其核心代码其实是这一句话:
if(nums[fast]!=val)
{
nums[slow]=nums[fast];
slow++;
}
当fast指针指向非val元素的时候,两个指针都向前运动,但是指向val元素的时候,只有fast指针运动,下次两个指针都运动时候的这个val元素,会被fast指针指向的非val元素替换。 下面是我的代码实现:
class Solution {
public int removeElement(int[] nums, int val) {
//首先来理解一下暴力解法,原地移除元素
//接下来实现一下双指针方法
//通过双指针的方法实现移除元素
int slow=0;
for(int fast=0;fast<nums.length;fast++){
if(nums[fast]!=val){
nums[slow]=nums[fast];
slow++;
}
}
return slow;
}
}
运行结果:
核心思想: 快指针可以理解成在旧数组中找非目标元素,然后赋值给慢指针指向的新数组。
算法时间:之前刷过一遍了,10分钟两道题目。
总结: 这两题之间有点类似的,他们都是在不断缩小 left 和 right 之间的距离,每次需要判断的都是 left 和 right 之间的数是否满足特定条件。对于「移除元素」这个写法本质上还可以理解为,我们拿 right 的元素也就是右边的元素,去填补 left 元素也就是左边的元素的坑,坑就是 left 从左到右遍历过程中遇到的需要删除的数,因为题目最后说超过数组长度的右边的数可以不用理,所以其实我们的视角是以 left 为主,这样想可能更直观一点。用填补的思想的话可能会修改元素相对位置,这个也是题目所允许的。