算法学习-二分法

  • 基础应用:在有序数组中找指定num
public class test1 {
    public static int sort(int[]arr,int num){
        if(arr==null||arr.length==0){
            return -1;
        }
        int L=0;
        int R=arr.length-1;
        while(L<=R){
            int mid=(R+L)/2;
            if(arr[mid]==num){
                return mid;
            }else if(arr[mid]<num){
                L=mid+1;
            }else if(arr[mid]>num){
                R=mid-1;
            }
        }
return -1;
    }
    public static void main(String[] args) {
        int[]arr={1,3,4,5,6,8,9,14,17,31};
        int a=sort(arr,1);
        System.out.println(a);
    }
}
  • 在有序数组中查找>=num的最左的位置【为了确定最左位置,会把整个数组切完】

    public static int mostLeft(int[]arr,int num){
        //保证arr有序
        if(arr==null||arr.length==0){
            return -1;
        }
        int L=0;
        int R=arr.length-1;
        //设置指针
        int ans=-1;
        while(L<=R){
            int mid=(R+L)/2;
            if(arr[mid]>=num){
            R=mid-1;
            ans=mid;
            }else{
                L=mid+1;
        }
        return ans;
    }
  • 局部最小值问题:无序数组中任意两个相邻位置不相等,局部最小比它相邻两数都小

    • 二分法不一定需要有序:

      • 如果arr[0]不是局部最小,说明arr[0]>arr[1] 【下降趋势】,又如果arr[N-1]不是局部最小,说明arr[N-2]>arr[N-1] 【上升趋势】,则arr[0]-arr[N-1]一定存在局部最小

      • 如果arr[mid]不是局部最小,说明arr[mid]>arr[mid-1] 或arr[mid+]【下降趋势】,则arr[0]-arr[mid]或arr[mid]-arr[N-1]一定存在局部最小

public class test2 {
//二分法找局部最小
    public static int findMin(int[] arr){
        int N = arr.length;
        int ans=-1;
        //如果为空,直接返回-1
        if(arr==null || N==0){
            return ans;
        }
        //如果数组长度为1,返回本身
        if(N==1){
            ans=arr[0];
            return ans;
        }
        //如果数组长度为2,返回最小数
        if(N==2){
            ans=arr[0]<arr[1]?arr[0]:arr[1];
            return ans;
        }
        //如果数组长度大于2
        int L=0;
        int R=N-1;
        //L到R肯定有局部最小,用二分法寻找
        while(L<R-1){
            int mid=(L+R)/2;
            //mid就是局部最小,小于其两边数
            if(arr[mid]<arr[mid-1]&&arr[mid]<arr[mid+1]){
                ans=mid;
                return ans;
            }else {
                //缩小范围
                if(arr[mid]>arr[mid-1]){
                    R=mid-1;
                }else if(arr[mid]>arr[mid+1]){
                    L=mid+1;
                }
            }
        }
       //到最后只剩L和R,L=R-1
        return arr[L]<arr[R]?L:R;
    }
//生成随机数组用于测试
    public static int[] RandomArr(int maxlength,int maxValue){
        //生成长度不超过maxlength随机长度数组
        int len=(int)(Math.random()*maxlength);
        int[] arr=new int[len];
        if(len>0){
           // 随机生成数值不超过maxvalue的arr[0]
            arr[0]=(int)(Math.random()*maxValue);
            //确保arr[i]!=arr[i+1}
            for (int i = 1; i <len ; i++) {
                do{
                    arr[i]=(int)(Math.random()*maxValue);

                }while(arr[i]==arr[i-1]);

            }
        }
        return arr;
    }
//用随机数组测试查找方法是否正确
    public static boolean check(int[]arr,int minIndex){
        if(arr.length==0){
            return minIndex==-1;
        }
        if(arr.length==1){
            return minIndex==0;
        }
        int left = minIndex - 1;
        int right = minIndex + 1;
        boolean leftBigger = left >= 0 ? arr[left] > arr[minIndex] : true;
        boolean rightBigger = right < arr.length ? arr[right] > arr[minIndex] : true;
        return leftBigger && rightBigger;

    }
    public static void main(String[] args) {
        int maxlength=100;
        int maxValue=1000;
        int[] arrs =RandomArr(maxlength, maxValue);
        int min = findMin(arrs);
        boolean check = check(arrs, min);
        System.out.println(check);

    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值