算法之二分查找

概述

二分查找算法的应用,包括有序和无序数据,有序数组默认按从小到大排序

在有序数组中找到num

java 复制代码
/**
     * 4 二分查找 在有序数组中找到num
     * 思路:找中值,然后中值元素和目标值比较。如果中值元素比目标值大,则继续在左半区域查找。反之,右半区。重复该过程,直至找到目标值
     * @param arr 数组
     * @param num 目标值
     * @return 返回目标值的索引
     */
    public static int binarySearch(int[] arr, int num){
        // 边界条件
        if(arr == null){
            return -1;
        }

        int l = 0;
        int r = arr.length-1;
        while(l <= r){
            int mid = l + (r-l)/2;
            if(arr[mid] == num){
                return mid;
            } else if (arr[mid] > num) {
                // 去左半区找
                r = mid - 1;
            } else{
                // 去右半区找
                l = mid + 1;
            }
        }

        return -1;
    }

在有序数组中找到最左边<=num的元素位置

java 复制代码
/**
     * 5 二分查找,在有序数组中找到>=num最左的位置
     * 思路:在原来的二分查找基础上,找到处于最左位置的target。
     * 每次二分找到目标值时,用临时变量记录此时的索引。再查找左半区是否还有target,如果有,则更新临时变量。
     * @param arr 数组
     * @param num 目标值
     * @return 最左位置的索引
     */
    public static int binarySearch2(int[] arr, int num){
        // 边界条件
        if(arr == null){
            return -1;
        }

        int l = 0;
        int r = arr.length-1;
        int ans = -1;
        while(l <= r){
            int mid = l + (r-l)/2;
            if(arr[mid] >= num){
                ans = mid;
                r = mid-1;
            }else{
                l = mid+1;
            }
        }
        return ans;
    }

在有序数组中找到最右边>=num的元素位置

java 复制代码
    /**
     * 6 二分查找,在有序数组中找到<=num的最右边的位置
     * 思路:二分得到中值,如果中值元素<=目标值,则检查中值的右边是否还有满足<=目标值的元素。反之查中值的左边。
     * @param arr 数组
     * @param num 目标值
     * @return 目标值的索引
     */
    public static int binarySearch3(int[] arr, int num){
        // 边界条件
        if(arr == null || arr.length == 1){
            return -1;
        }

        int l = 0;
        int r = arr.length-1;
        int ans = -1;
        while(l <= r){
            int mid = l + (r-l)/2;
            if(arr[mid] <= num){
                ans = mid;
                l = mid + 1;
            }else{
                r = mid - 1;
            }
        }

        return ans;
    }

logn时间复杂度的无序数组寻找局部最值

java 复制代码
/**
 * 寻找峰值:<a href="https://leetcode.cn/problems/find-peak-element/description/">...</a>
 * 在无序,相邻元素不相等的列表中返回任一局部最小值
 * 思路:通过二分降低时间复杂度,提升效率。找到中值后,判断中值元素临近的mid-1、mid+1的关系。
 * 最值要么出现在数组两端,要么出现在中间。
 * 在无序数组中,找到中值后,如果arr[mid-1] < arr[mid] < arr[mid+1],那么在0-mid之间一定存在一个最小值。
 * 所以剩下就是二分找到这个最小值。
 * @author Kenyi
 */
public class LocalMinValue {

    public static void main(String[] args) {
        int length = 9;
        int maxValue = 10;
        int testCycle = 100000;
        for (int i = 0; i < testCycle; i++) {
            int[] arr = randomArray(length, maxValue);
            int minIndex = binarySearchValleyElement(arr);
            if(!check(arr, minIndex)){
                System.out.println("出错了!");
                System.out.println("minIndex: " + minIndex);
                printArr(arr);
            }
        }
    }

    /**
     * 8 二分查找局部最小值算法
     * @param arr 数组
     * @return 目标值索引
     */
    public static int binarySearchValleyElement(int[] arr){
        // 边界条件
        if(arr == null ){
            return -1;
        }
        int length = arr.length;
        if(length == 0){
            return -1;
        }

        if(length == 1){
            return 0;
        }
        if(arr[0] < arr[1]){
            return 0;
        }
        if(arr[length -1] < arr[length -2]){
            return length -1;
        }

        int left = 0;
        int right = length -1;
        while(left <= right){
            int mid = left + (right - left)/2;
            if(arr[mid-1] < arr[mid]){
                right = mid-1;
            } else if (arr[mid] > arr[mid+1]) {
                left = mid+1;
            }else{
                return mid;
            }
        }

        return -1;
    }

    /**
     * 返回数组任一的局部最大值
     * @param arr 数组
     * @return 局部最大值的索引
     */
    public static int findPeakElement(int[] arr) {
        int n = arr.length;
        if (arr.length == 1) {
            return 0;
        }
        if (arr[0] > arr[1]) {
            return 0;
        }
        if (arr[n - 1] > arr[n - 2]) {
            return n - 1;
        }
        int l = 1, r = n - 2, m = 0, ans = -1;
        while (l <= r) {
            m = (l + r) / 2;
            if (arr[m - 1] > arr[m]) {
                r = m - 1;
            } else if (arr[m] < arr[m + 1]) {
                l = m + 1;
            } else {
                ans = m;
                break;
            }
        }
        return ans;
    }

    /**
     * 生成随机数组
     * @param length 数组长度
     * @param maxValue 元素最大值
     * @return 生成的数组
     */
    public static int[] randomArray(int length, int maxValue){
        // 边界条件
        int[] arr = new int[length];
        if(length == 0){
            return arr;
        }
        arr[0] = (int)(Math.random() * maxValue);
        if(length == 1){
            return arr;
        }

        // 相邻元素互不相等
        for (int i = 1; i < length; i++) {
            do{
                arr[i] = (int)(Math.random() * maxValue);
            }while (arr[i] == arr[i-1]);
        }

        return arr;
    }

    /**
     * 检查是否是局部最小值
     * @param arr 数组
     * @param index 索引
     * @return 布尔值
     */
    public static boolean check(int[] arr, int index){
        if(arr == null || arr.length == 0){
            return index == -1;
        }

        if(index == -1){
            for (int i = 1; i < arr.length-1; i++) {
                if(arr[i-1] > arr[i] && arr[i] < arr[i+1]){
                    return false;
                }
            }
            return true;
        }

        int left = index-1;
        int right = index+1;
        boolean leftOk = left < 0 || arr[left] > arr[index];
        boolean rightOk = right > arr.length - 1 || arr[index] < arr[index + 1];

        return leftOk && rightOk;
    }

    /**
     * 打印数组
     * @param arr 数组
     */
    public static void printArr(int[] arr){
        System.out.println(Arrays.toString(arr));
    }
相关推荐
卓码软件测评12 分钟前
第三方软件测试机构【性能测试工具用LoadRunner还是JMeter?】
java·功能测试·测试工具·jmeter·性能优化
Lionel_SSL4 小时前
《深入理解Java虚拟机》第三章读书笔记:垃圾回收机制与内存管理
java·开发语言·jvm
记得开心一点嘛4 小时前
手搓Springboot
java·spring boot·spring
Greedy Alg4 小时前
LeetCode 142. 环形链表 II
算法
睡不醒的kun4 小时前
leetcode算法刷题的第三十二天
数据结构·c++·算法·leetcode·职场和发展·贪心算法·动态规划
老华带你飞4 小时前
租房平台|租房管理平台小程序系统|基于java的租房系统 设计与实现(源码+数据库+文档)
java·数据库·小程序·vue·论文·毕设·租房系统管理平台
独行soc4 小时前
2025年渗透测试面试题总结-66(题目+回答)
java·网络·python·安全·web安全·adb·渗透测试
脑子慢且灵5 小时前
[JavaWeb]模拟一个简易的Tomcat服务(Servlet注解)
java·后端·servlet·tomcat·intellij-idea·web
先做个垃圾出来………5 小时前
残差连接的概念与作用
人工智能·算法·机器学习·语言模型·自然语言处理
华仔啊6 小时前
SpringBoot 中 6 种数据脱敏方案,第 5 种太强了,支持深度递归!
java·后端