欢迎使用Markdown编辑器
二分法
头条面试题
Q: 形如这样的无序数组 [1,1,2,2,3,4,4,6,6,5,5,8,8] ,除了一个数字只会出现一次,其他数字成对出现而且相邻排列,找出只出现一次的这个数字。
[1,1,2,2,3]
public class Main {
public static void main(String[] args) {
int []arr={1,1,2,2,3,3,5,4,4,6,6,5,5,8,8};
int result=binarySearch(arr);
System.out.println(result);
}
public static int binarySearch(int[]arr)
{
int low=0;
int high=arr.length-1;
//闭区间
while(low<=high)
{
if(low==high)
return arr[low];
int mid=low+(high-low)/2;
//中间这个数就是单独出现的
if(arr[mid]!=arr[mid-1] && arr[mid]!=arr[mid+1])
{
return arr[mid];
}
//中间的数,相同的数出现在右边
else if(arr[mid]==arr[mid+1])
{
int right_length=(arr.length-1)-(mid+1);
if(right_length%2==0)
{
high=mid-1;
}
else if(right_length%2==1)
{
low=(mid+1)+1;
}
}
//中间的数,相同的数出现在左边
else if(arr[mid]==arr[mid-1])
{
int left_length=(mid-1)-0;
if(left_length%2==0)
{
low=mid+1;
}
else if(left_length%2==1)
{
high=(mid-1)-1;
}
}
}
return arr[high];
}
}
二分法找左侧边界
public class Main {
public static void main(String[] args) {
int[] arr = {1,2,2,2,3};
int left_bound=left_bound(arr,9);
System.out.println(left_bound);
}
public static int left_bound(int []arr,int target)
{
if(arr.length==0)
return -1;
//左闭右开区间
int left=0;
int right=arr.length;
while(left<right) //[left,left)时,结束循环,left=right时
{
int mid=left+(right-left)/2;
if(arr[mid]==target)
{
//去掉mid,向左搜索 [left,mid)
right=mid;
}
else if(arr[mid]<target)
{
//去掉mid,向右搜索[mid+1,right)
left=mid+1;
}
else if(arr[mid]>target)//[left,mid)
{ //去掉mid,向左搜索
right=mid;
}
}
//left=right
if(left<0 ||left>=arr.length)
return -1;
return left;
}
}
二分法搜索右侧边界
public static int right_bound(int[]arr,int target){
if(arr.length==0)
return -1;
int left=0;
int right=arr.length-1;
while(left<=right)
{
int mid=left+(right-left)/2;
if(arr[mid]==target)
{
left=mid+1;
}
else if(arr[mid]<target)
{
left=mid+1;
}
else if(arr[mid]>target)
{
right=mid-1;
}
}
//left=right+1;
if(right>=arr.length || right<0)
return -1;
return right;
}
3、二分查找旋转数字(一定要注意三个等号)
nums[mid]和target在左升序的时候,一定要记得判断条件加上等号。
if(nums[mid]>=nums[0])
if(target>=nums[0])
class Solution {
public static int search(int[] nums, int target) {
if(nums.length==0)
return -1;
int left=0;
int right=nums.length-1;
while(left<=right)
{
int mid=left+(right-left)/2;
if(nums[mid]==target)
return mid;
else if(nums[mid]>=nums[0])//在左升序 //一定要注意这个等号
{
if(nums[mid]>target)
{
if(target>=nums[0]) //一定要注意这个等号
right=mid-1;
else if(target<nums[0])
left=mid+1;
}
else if(nums[mid]<target)
{
if(target>nums[0])
left=mid+1;
//这种情况不可能出现if(target<nums[0]
}
}
else if(nums[mid]<nums[0])//在右升序
{
if(nums[mid]>target)
{
if(target<nums[0])
right=mid-1;
//这种情况不可能出现else if(target>nums[0])
}
else if(nums[mid]<target)
{
if(target<nums[0])
left=mid+1;
else if(target>=nums[0]) //注意这个等号
right=mid-1;
}
}
}
return -1;
}
}