今日的第一题是数组的二分查找;
二分时应当给出左侧以及右侧,
本题的关键实际上就是对于终结时刻的判断——即while什么时候结束
以及一个最重要的问题
关键在于,当我们在查找到中间值后,取中间值的两侧,中间值所在的位置应当被舍弃,理解了这一点才能更好的理解到我们在左闭右闭以及左闭右开的区间中的对于right 和 left 的更新的处理
循环不变量
*对于区间的定义,区间定义的关键即为不变量,要在二分查找的过程中,保持不变量,在每次while寻找中对于每次边界的处理都要坚持根据区间的定义进行操作
通常对于区间的定义有两种:
-
左闭右开[left,right)
在此种情形下,有如下两点应当注意:
- 在结束循环的判断中,应当使用while(left < right) ,这是由于left = right 是无法做到的
- if(nums[mid] > target)中 right 更新为 mid,因为当前nums[mid] ≠ target, 因此可以直接将区间的右端定义为mid的当前值
具体的左闭右开代码书写如下:
public class Solution { public int search(int[] nums, int target) { //最应当做的应该首先是特殊情况处理 if(nums.length==0){ return -1; } //对于左闭右开的情况的处理 int left = 0; int right = nums.length; int mid; while(left < right){ //mid常态化变化 mid = (left + right) / 2; if(nums[mid] < target){ left = mid+1; } else if(nums[mid] > target){ right = mid; } else{ return mid; } } return -1; } }
-
左闭右闭[left,right]
此时有如下两点需要注意:
- 在while结束的判断中,应当使用while(left ≤ right),这是出于确实存在着left == right 的情形去实际考虑的
- if(nums[mid] > target) 中 right需要赋值为 mid -1, 因为当前的nums[mid] 一定不是target,则接下来需要查找的左区间结束的下标位置为 mid-1。 同理,left在其对应的情形下应当赋值为 mid + 1
具体的左闭右闭代码书写如下:
public class Solution {
public int search(int[] nums, int target) {
//最应当做的应该首先是错误处理
if(nums.length==0){
return -1;
}
//定义左边、右边,每次查找后修改查找的边界
int len = nums.length;
int left = 0;
int right;
//此处定义为左闭右闭区间
right = len-1;
int mid = (left+right)/2;
//当左右相邻时结束,存在左==右情况,故此处为<=
while(left <= right){
//mid应该成为常态形变化变量,每次都应该更改
mid = (left + right) / 2;
//中间位置的值更小一些
if(nums[mid] < target){
left = mid + 1;
}
//中间值更大
else if(nums[mid] > target){
right = mid - 1;
}
else{
return mid;
}
}
return -1;
}
}
27.移除元素
看到这道题,我心中最朴素的想法就是直接使用后来的元素去替代原位置上的元素,即两次遍历,这样就能够完成题目条件,将需要移除的元素后面的元素全部向前移动一位。
代码如下:
public class Solution {
public int removeElement(int[] nums, int val) {
int sum = nums.length;//sum代表了整个数组中的元素个数
for(int i = 0; i < sum;i++){
if(nums[i] == val){
//此处应当注意是否会发生栈溢出
for(int j = i+1; j < sum;j++){
nums[j-1] = nums[j];
}
i--;//由于少了一个元素,因此应当重新遍历刚刚移动过来的元素
sum--;//注意sum中的元素个数是在动态变化的,如果不是如此使用,可能会造成栈溢出等问题?
}
}
return sum;
}
}
双指针法
通过一个快指针和一个慢指针在一个for循环下完成两个for循环的工作
- 快指针:寻找新数组的元素,新数组就是不含有目标元素的数组
- 慢指针:指向更新的新数组下标的位置
删除过程如下图:
代码如下:
public class Solution {
public int removeElement(int[] nums, int val) {
//双指针法处理如下:
int slowIndex = 0;
for(int fastIndex = 0; fastIndex < nums.length;fastIndex++){
if(val != nums[fastIndex]){
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;
}
}
本日是我跟随代码随想录进行训练的第一天,时间也是来的颇为匆忙,在这为期两个月的时间中,我相信自己定会有所收获。
未来漫长,一定努力。
祝你,也祝我