学习数据结构笔记(15) --- [二分查找算法(非递归)]

Posted 小智RE0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习数据结构笔记(15) --- [二分查找算法(非递归)]相关的知识,希望对你有一定的参考价值。

力扣这道题其实就是二分查找的基础考察题目
704. 二分查找
写完可以多找几道二分查找的题试试

二分查找的前提是这个数组是一个有序的数组;
我们这里将规定为升序数组;

定义中间数值的索引; 若要找的目标值就是这个中间值,直接返回即可;
若找的目标值大于中间数,则将查询范围缩小到中间数的右边;
若找的目标值小于中间数,则将查询范围缩小到中间数的左边;

/**
     * 在升序数组中查找目标数值的索引;
     * @param array  升序的数组;
     * @param target 目标值;
     * @return 返回目标值的索引,找不到就返回-1;
     */
    public static int binarySearch(int[] array, int target)
        //定义左右指针,
        int left = 0;
        int right = array.length-1;
        
        while (left<=right)
            //中点;
            int middle = left+( right -left)/2;
            //若找到目标数返回;若大于目标数,在左边查找; 小于目标数,在右边查找;
            if(array[middle] == target) 
                return middle;
            if(array[middle] > target)
                right = middle - 1;
            if (array[middle] < target)
                left = middle + 1;
        
        //若没找到,返回-1;
        return -1;
    

还可以用这个模板进行查找

class Solution 
    public int search(int[] nums, int target) 
       //先临时统计,查找是否有目标值;
       int temp = 0 ;
       for(int i =0;i<nums.length;i++)
           if(nums[i]==target)
           temp ++;
       
       
       //若没有目标值,直接结束;
       if(temp == 0) return -1;
       if(nums.length == 0) return -1;
       //定义左右指针,
       int left = -1;
       int right = nums.length;
       int middle=0;
       while(left+1!=right)
           middle = left + (right-left)/2;
           if(nums[middle] < target)
               left = middle;
           else
               right = middle;
           
           //if(middle<0||middle == nums.length-1) break;
       
       return nums[right] == target ?right:-1;
    

力扣34题:在排序数组中查找元素的第一个出现位置,以及最后一次出现位置;若不存在则返回-1;将两个结果封装到数组中;
34. 在排序数组中查找元素的第一个和最后一个位置

题目描述:

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:
你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?
 
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例 2:
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

示例 3:
输入:nums = [], target = 0
输出:[-1,-1]

提示:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums 是一个非递减数组
-109 <= target <= 109

使用二分查找模板;
找第一个目标元素时,找到第一个小于目标值的位置即可;返回的是最后的右指针位置;注意,有可能找不到指定的元素;若此时的位置不是目标元素;就说明不存在,返回-1;
找第二个目标元素时,找到第一个大于目标值的位置即可,但会的是最后的左指针位置;注意,这时也有可能找不到指定元素,若此时的位置不是目标元素,说明不存在,返回-1;

class Solution 
    public int[] searchRange(int[] nums, int target) 
       //若数组长度为0,或者当前目标元素并不存在,则返回数组[-1,-1]
       if(nums.length==0 ||nums[0]>target||nums[nums.length-1]<target) return new int[]-1,-1;
       int[] res = new int[2];
        //查找第一个目标数;
        int l1 = -1;
        int r1 = nums.length;
        int mid1 = 0;
        while(l1+1!=r1)
            //计算中值;
            mid1 = l1+(r1-l1)/2;
            if(nums[mid1] < target)
                  l1 = mid1;
            else
              r1 = mid1;
            
        
        //找到第一个数就是在中值的右边;
        res[0] =  (nums[r1]==target)?r1:-1;
        
        //找第二个数;
        int l2 = -1;
        int r2 = nums.length;
        int mid2 = 0;
        while(l2+1!=r2)
            //计算中值;
            mid2 = l2+(r2-l2)/2;
            if(nums[mid2] <= target)
                l2 = mid2;
            else
                r2 = mid2;
            
        
        //找到最后一次出现的数;
        res[1]=  (nums[l2]==target)?l2:-1;
        return res;
    

封装到方法中

/**
 * @author by CSDN@小智RE0
 * @date 2021-11-26 17:45
 */
public class BSDemo 
    public static void main(String[] args) 

        int[] arr = 1,3,3,3,3,6,9,12,53;
        int index = getFirst(arr, 3);
        System.out.println("第一次出现的位置-->"+index);
        //找到第一个出现的元素;
        int last = getLast(arr, 3);
        System.out.println("最后一次出现的位置-->"+last);
    

    /**
     * 找到目标元素第一次出现的索引;
     *
     * @param arr    需要查询的升序数组;
     * @param target 目标元素
     * @return 目标元素第一次出现的索引, 若不存在则返回-1;
     */
    public static int getFirst(int[] arr, int target) 
        //若不符合,直接返回;
        if (arr.length == 0 || arr[0] > target || arr[1] < target)
            return -1;
        //定义左右指针;中轴索引;
        int left = -1;
        int right = arr.length;
        int middle;
        while (left + 1 != right) 
            //计算中轴索引;
            middle = left + (right - left) / 2;
            if (arr[middle] < target) 
                left = middle;
             else 
                right = middle;
            
        
        return (arr[right] == target) ? right : -1;
    

    /**
     * 找到目标元素最后一次出现的索引;
     * @param arr 需要查询的升序数组
     * @param target 目标元素
     * @return 目标元素最后一次出现的索引, 若不存在则返回-1;
     */
    public static int getLast(int[] arr,int target)
        //定义左右指针;中轴索引;
        int left = -1;
        int right = arr.length;
        int middle;
        while (left + 1 != right) 
            //计算中轴索引;
            middle = left + (right - left) / 2;
            if (arr[middle] <= target) 
                left = middle;
             else 
                right = middle;
            
        
        return (arr[left] == target) ? left : -1;
    

以上是关于学习数据结构笔记(15) --- [二分查找算法(非递归)]的主要内容,如果未能解决你的问题,请参考以下文章

「算法笔记」一文摸秃二分查找

复盘笔记二分查找和大O表示法

数据结构与算法学习笔记 查找

数据结构与算法学习笔记 查找

数据结构和算法————二分查找

数据结构学习笔记——查找算法