二分法-20200726

本文探讨了二分法在解决面试问题中的应用,包括寻找无序数组中唯一数字的左侧和右侧边界,以及在旋转数组中的二分查找。特别强调在处理不同情况时,如在升序部分的条件判断中需包含等于号。
摘要由CSDN通过智能技术生成

欢迎使用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;                                                             
                                                                               
    }                                                                          
        
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值