程序员必备十种算法之——二分搜索算法

16 篇文章 0 订阅
2 篇文章 0 订阅

二分查找算法(递归版)

问题描述:

请对一个有序(在这讲的是升序)的数组{1,4,9,11,33,41,69,72,99}进行二分查找,输入一个数看看该数组是否存在该数,并且求出下标,如果没有就返回提示没有这个数。

二分查找思路分析:(对一个有序的数组进行查找)

1.首先确定该数组的中间下标(在这用mid来表示)
mid = (left + right)/2

2.然后让需要查找的数(findVal)与arr[mid]做比较:
1)findVal > arr[mid],说明要查找的数在mid的右边,因此需要递归向右查找
2)findVal < arr[mid],说明要查找的数在mid的左边,因此需要递归向左查找
3)findVal == arr[mid],说明找到,返回

什么时候应该结束递归:
1)找到就结束递归
2)递归完整个数组,仍然没有找到findVal,也需要结束递归(即当left > right)

有人看到这里可能就要疑问了?诶,凭什么left > right,就结束递归了?你说结束就结束是么?别急,看完下面你就明白了(实在不明白的话,可以自己选一个小一点的数组,自己推一遍,我一开始也是一头雾水,后面自己推了一遍过程就很清晰了)

left > right(边界条件):

由题意,在这讲的是升序(降序相反),我们可以知道当寻找一个数时,总要要移动 left 或 right 的下标。

例如:
向左递归时,我们left不变,right等于mid-1(相当于向左移动)
向右递归时,我们right不变,left等于mid+1(相当于向右移动)

只要数组不是无限大的,那么 left 一直向右移动,right 一直向左移动,总有一次当 left > right 时代表所有数都已经找完了,没有找到,这时候就应该停止递归,返回-1,提示我们没有找到这个值了。

代码:

public class BinarySearch {
	public static void main(String[] args) {
        int[] arr = new int[]{1,4,9,11,33,41,69,72,99};
        int index = binarySearch(arr,0,arr.length-1,99);
        System.out.printf("index:"+index);
    }
	public static int binarySearch(int[] arr,int left,int right,int findVal) {
        if(left > right){
            return -1;//未找到用-1表示
        }
        int mid = (right + left) / 2;
        int midVal = arr[mid];
        //找到就返回下标
        if(findVal > midVal){//要查找的数在mid的右边,向右递归
            return binarySearch(arr,mid +1 ,right,findVal);
        }else if (findVal < midVal){//要查找的数在mid的左边,向左递归
            return binarySearch(arr,left,mid -1,findVal);
        }else {//findVal == arr[mid]
            return mid;
        }
    }
}

>>index:8

扩展:

若数组为{1,49,64,81,666,666,666,1264},当一个有序数组中,有多个相同的数值时如何将所有的数值都查找到,例如这里的元素666。

思路分析:

1.我们用一个ArrayList来接收要找的所有相同数值的索引
2.在找到mid索引值时,不要立刻返回
3.向mid索引值的左边扫描,将所有满足666元素的下标,加入到集合ArrayList中
4.向mid索引值的右边扫描,将所有满足666元素的下标,加入到集合ArrayList中

代码:

public class BinarySearch2 {
	public static void main(String[] args) {
        int[] arr = new int[]{1,49,64,81,666,666,666,1264};
        List<Integer> resIndexList = binarySearch(arr,0,arr.length-1,666);
        System.out.printf("resIndexList:" + resIndexList);
    }
    public static List<Integer> binarySearch(int[] arr,int left,int right,int findVal){
        if(left > right){
            return new ArrayList<Integer>();
        }

        int mid = (left + right) / 2;
        int midVal = arr[mid];
        if(findVal > midVal){
            return binarySearch(arr,mid+1,right,findVal);
        }else if(findVal < midVal){
            return binarySearch(arr,left,mid-1,findVal);
        }else {
            List<Integer> resIndexList = new ArrayList<Integer>();
            //向mid左边扫描
            int temp = mid-1;
            while (true){
                if(temp < 0 || arr[temp] != findVal){   //说明到最左边了,或者前一个数不是要找的目标值
                    break;
                }
                //否则就放入进集合中
                resIndexList.add(temp);
                temp -= 1;
            }
            resIndexList.add(mid);//将mid放入集合中
            temp = mid + 1;
            //向mid右边扫描
            while (true){
                if(temp > arr.length-1 || arr[temp] != findVal){
                    break;
                }
                //否则放入集合中
                resIndexList.add(temp);
                temp += 1;
            }
            return resIndexList;
        }
    }
}


>>resIndexList:[4, 5, 6]

二分查找算法(非递归版)

时间复杂度:

二分查找法的运行时间为对数时间O(log2n),即查找到需要的目标位置最多只需要 log2n 步,假设从[0,99]的数列(100个数,即 n = 100)中寻到目标元素30,则需要查找步数为 log2 100,即最多需要查找7次
(2^6 < 100 < 2^7)

思路分析:

同递归的思路一样,唯一不同的就是边界条件变为了left < = rigth

代码:

public static void main(String[] args) {
        int[] arr = new int[]{1,4,9,11,33,41,69,72,99};
        int index = binarySerch(arr,99);
        System.out.printf("index:" + index);
    }
    public static int binarySerch(int[] arr,int target){
        int left = 0;
        int right = arr.length - 1;
        while(left <= right){//在递归的时候说过,left > right是它的一个边界条件
            int mid = (left + right) / 2;
            if(target > arr[mid]){
                left = mid + 1; //向右递归
            }else if (target < arr[mid]){
                right = mid - 1;  //向左递归
            }else {//target == arr[mid]说明找到了
                return mid;
            }
        }
        return -1;//-1代表没找到
    }
}

二分查找我们就讲到这里,下面我会更新在Leetcode里所归为二分查找类型的算法题型解法:

35.搜索插入位置

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值