二分查找
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length-1;
if(nums[right]<target) return -1;
while(left<=right){ //左闭右闭 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;
}
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length;
//if(nums[right]<target) return -1;
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;
}
本题总结
1. 在刚开始的边界判定时,左闭右闭可以判断num[right] 和 mid是否相等,而左闭右开则不行,会越界。
2. 将 mid 由 (left+right)/2 写成 left + (right-left)/2或者 left + (right-left)> 1 都可以防止溢出,区别是位运算比直接相除的操作快(对于二进制的正数来说,右移x位相当于除以2的x几次方,所以右移一位等于除以2)。
public int searchInsert(int[] nums, int target) {
int left = 0;
int 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 left;
}
public int[] searchRange(int[] nums, int target) {
int start = red_blue(nums, target);
if(start== nums.length || nums[start]!= target) return new int[]{-1,-1};
int end = red_blue(nums,target+1)-1;
return new int[]{start,end};
}
public int red_blue(int[] nums, int target){
int left=0;
int right = nums.length-1;
while(left<=right){
int mid = left + (right-left)/2;
if(nums[mid]<target){
left = mid+1;
}else{
right = mid-1;
}
}
本题总结
红蓝染色法,二分完之后l-1之前的部分全是红色,r+1之后的全是蓝色,所以l或者r+1的位置就收start的起始位置,end则是取到target+1的位置的前一个位置,也就是target的最后一个位置。
69.x 的平方根
public int mySqrt(int x) {
if(x==0|| x==1) return x;
int left=0;
int right=x;
while(left<=right){
int mid = left+(right-left)/2;
if((long)mid*mid>x){
right = mid-1;
}else{
left = mid+1;
}
}
return left-1;
}
public boolean isPerfectSquare(int num) {
if(num == 0 || num == 1) return true;
int left=0;
int right=num;
while(left<=right){
int mid = left + (right-left)/2;
if((long)mid*mid>num){
right = mid-1;
}else if((long)mid*mid<num){
left = mid+1;
}else{
return true;
}
}
return false;
}
双指针
暴力法
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++){//如果j=i 则当i=0时,j-1=-1越界
nums[j-1] = nums[j];
}
size--; //当for循环结束时 size和i就--
i--;
}
}
return size;
}
双指针
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];
}
}
return slow;
}
本题总结
主要是要注意暴力法中的边界问题。