学习目标:
1.二分查找的模板与应用
2.移除元素
1.704二分查找
学习中发现了网上有许多二分模板,再初步学习后发现只需要背下其中一个万能的模板就行了
万能模板:
①先定义左闭右闭区间 (l,r)
②定义中间值mid
③通过判断语句判断mid值在结果的左边或者右边,进行l = mid+1或者r = mid -1缩短区间的操作
④左区间大于右区间时停止循环,答案为 l+1
public static int search(int[] nums, int target) {
Arrays.sort(nums);
int l = 0 , r = nums.length-1;
while(l <= r){
int mid = (r-l)/2+l;//防止溢出
if(check())
l = mid+1;
else
r= mid-1;
}
return l-1;
}
在代码中,我改进了左闭右闭区间的代码,使其更简洁(好记)。原来的代码是l = mid,return mid,改成了l = mid+1,r = mid-1的形式更好记。
代码:
import java.util.Arrays;
class Solution {
public int search(int[] nums, int target) {
Arrays.sort(nums);
int l = 0 , r = nums.length-1;
if(nums[l] > target || nums[r] < target)return -1;
while(l <= r){
int mid = (r-l)/2+l;
if(nums[mid] <= target)
l = mid+1;
else
r= mid-1;
}
return (nums[l-1] == target ? l-1 : -1);
}
}
代码:如果查找到就返回答案,查找不到就返回查找到的最后的位置的右边一位(r+1)
class Solution {
public int searchInsert(int[] nums, int target) {
int l = 0 , r = nums.length-1;
if(nums[0] > target) return 0;
if(nums[r] < target) return nums.length;
while(l <= r){
int mid = (r-l)/2+l;//防止溢出
if(nums[mid] <= target)
l = mid+1;
else
r= mid-1;
}
return nums[l-1] == target ? l-1:r+1;
}
}
代码:运用两个二分查找,第一个二分查找最右边的target的下标,第二个查找最左边的下标,模板的运用很有讲究,要特别辨认从左往右找还是从右往左找。
比如第一个二分 if(nums[mid] <= target) 返回的r就是答案,则是右区间。
class Solution {
public int[] searchRange(int[] nums, int target) {
int l = 0; int r = nums.length-1;
while(l<=r){
int mid = (r-l)/2+l;
if(nums[mid] <= target)
l = mid +1;
else
r = mid -1;
}
if(l-1<0 ||l-1 > nums.length || nums[l-1] != target)//如果超出数组范围或者是找不出答案则返回-1
return new int[]{-1,-1};
int R = l-1;//记录右边界
l = 0; r = nums.length - 1;
while(l<=r){
int mid = (r-l)/2+l;
if(nums[mid] >= target)
r = mid-1;
else
l = mid+1;
}
int L = r+1;//纪录左边界
return new int[]{L,R};
}
}
2.移除元素
暴力解法:利用两个for循环,把i后面的所有数字往前移一位,时间复杂度O(n^2)。
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<nums.length;j++){
nums[j-1] = nums[j];
}
i--;
size --;
}
}
return size;
}
}
双指针解法:快指针寻找可以放进新数组的元素,慢指针指的是新数组的下标,时间复杂度O(n)
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;
}
}