代码随想录打卡打一天|704.二分查找,27.移除元素
二分查找
左闭右开或者左闭右闭都表示mid的取值范围,
mid取值:
left=0,right=nums.length(左闭右开,左边界取,右边界无效,不取)
or
left=0, right = nums.length - 1(左闭右闭,左边界取,右边界有效,取)
随着范围不断缩小,
终止条件:
不论是左闭右开还是左闭右闭要遍历完整个数组,但由于mid的取值范围不同,导致终止条件不同
while(left<right) (左闭右开,终止时:right=left,因为right本来就无效,所以整个数组遍历完毕)
or
while(left<=right) (左闭右闭,终止时:right<left,该情况下左右边界都有效,必须查看right=left,整个数组遍历完毕)
比较时的判断条件:
左闭右开:
if(nums[mid] > target){
right = mid ;
}else if(nums[mid] < target){
left = mid + 1;
}else{
return mid;
}
左闭右闭
if(nums[mid] > target){
right = mid - 1 ;
}else if(nums[mid] < target){
left = mid + 1;
}else{
return mid;
}
区别在于右边界有无效,左闭右开,右边界无效,则同样去无效的mid
左闭右闭,右边界有效,则取有效的mid - 1
整体代码
左闭右开
class Solution {
public int search(int[] nums, int target) {
//左闭右开
int left = 0 , right = nums.length;
while(left < right){
int mid = left + (right - left)/2;
if(nums[mid] > target){
right = mid ;
}else if(nums[mid] < target){
left = mid + 1;
}else{
return mid;
}
}
return -1;
}
}
左闭右闭
class Solution {
public int search(int[] nums, int target) {
//左闭右闭
int left = 0 , right = nums.length - 1;
while(left <= right){
int mid = left + (right - left)/2;
if(nums[mid] > target){
right = mid - 1;
}else if(nums[mid] < target){
left = mid + 1;
}else{
return mid;
}
}
return -1;
}
}
拓展题
在排序数组中查找元素的第一个和最后一个位置
class Solution {
public int[] searchRange(int[] nums, int target) {
int start = startIndex(nums,target);
int end = endIndex(nums,target);
if(start == -2 || end == -2 )return new int[]{-1,-1};
if(end - start >= 1)return new int[]{start,end};
return new int[]{-1,-1};
}
//返回第一个下标,或者返回第一个小于的下标,
//[5,7,7,8,8,10]
//8
int startIndex(int[] nums , int target){
int left = 0 , right = nums.length-1;
int find= -2;
while(left <= right){
int mid = left + (right - left)/2;
if(nums[mid] > target){
right = mid-1;
}else if(nums[mid] < target){
left = mid + 1;
}else{
//如果相等,则判断右边一个是否符合条件
find=right;
right = mid - 1;
}
}
return find;
}
int endIndex(int[] nums , int target){
int left = 0 , right = nums.length-1;
int find= -2;
while(left <= right){
int mid = left + (right - left)/2;
if(nums[mid] > target){
right = mid - 1;
}else if(nums[mid] < target){
left = mid+1;
}else{
find = left;
left = mid + 1;
}
}
return find;
}
}
移除元素
一个简单的快慢指针(一个简单的快慢口儿,在家就能做(狗头.jpg))
class Solution {
public int removeElement(int[] nums, int val) {
//慢指针记录最终答案,快指针扫描数组,如果符合条件则用快指针指向的元素,覆盖慢指针指向的元素
int low = 0;
for(int fast = 0 ; fast < nums.length ; fast++){
if(nums[fast] != val){
nums[low++] = nums[fast];
}
}
return low;
}
}