当前位置: 首页 > article >正文

算法总结-二分查找

文章目录

    • 1.搜索插入位置
        • 1.答案
        • 2.思路
    • 2.搜索二维矩阵
        • 1.答案
        • 2.思路
    • 3.寻找峰值
        • 1.答案
        • 2.思路
    • 4.搜索旋转排序数组
        • 1.答案
        • 2.思路
    • 5.在排序数组中查找元素的第一个和最后一个位置
        • 1.答案
        • 2.思路
    • 6.寻找旋转排序数组中的最小值
        • 1.答案
        • 2.思路

1.搜索插入位置

1.答案
package com.sunxiansheng.arithmetic.day18;

/**
 * Description: 35. 搜索插入位置
 *
 * @Author sun
 * @Create 2025/1/30 10:11
 * @Version 1.0
 */
public class t35 {

    public static int searchInsert(int[] nums, int target) {
        // 左闭右闭,加等号
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            // 求中点
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) {
                return mid;
            }
            if (nums[mid] < target) {
                left = mid + 1;
            }
            if (nums[mid] > target) {
                right = mid - 1;
            }
        }
        // 如果找不到,就返回应该插入的位置
        return left;
    }
}
2.思路

左闭右闭,加等号,求中点,找不到就返回left

2.搜索二维矩阵

1.答案
package com.sunxiansheng.arithmetic.day18;

/**
 * Description: 74. 搜索二维矩阵
 *
 * @Author sun
 * @Create 2025/1/30 10:16
 * @Version 1.0
 */
public class t74 {

    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length;
        int n = matrix[0].length;
        // 左闭右闭
        int left = 0, right = m * n - 1;
        // 加等号
        while (left <= right) {
            // 求中点
            int mid = left + (right - left) / 2;
            // 转换中点下标为二维数组的下标
            int i = mid / n;
            int j = mid % n;
            if (matrix[i][j] == target) {
                return true;
            }
            if (matrix[i][j] < target) {
                left = mid + 1;
            }
            else if (matrix[i][j] > target) {
                right = mid - 1;
            }
        }
        return false;
    }
}
2.思路

就是在求中点的时候有些不一样,需要将数字转换为二维数组的下标,公式就是x / n 和 x % n

3.寻找峰值

1.答案
package com.sunxiansheng.arithmetic.day18;

/**
 * Description: 162. 寻找峰值
 *
 * @Author sun
 * @Create 2025/1/30 10:35
 * @Version 1.0
 */
public class t162 {

    public int findPeakElement(int[] nums) {
        // 左闭右闭加等号
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            // 判断是否大于左右边元素
            boolean leftSmaller = mid == 0 || nums[mid] > nums[mid - 1];
            boolean rightSmaller = (mid == nums.length - 1) || nums[mid] > nums[mid + 1];
            // 如果都大于,则当前元素就是峰值
            if (leftSmaller && rightSmaller) {
                return mid;
            }
            // 如果比左边的元素大,则峰值在右边
            if (leftSmaller) {
                left = mid + 1;
            } else {
                // 其余情况峰值在左边
                right = mid - 1;
            }
        }
        return -1;
    }
}
2.思路

除了二分老套路之外,还要判断是否大于左右边元素,如果都大于就是峰值,如果只是大于左边但是小于右边,那么峰值就在右边

4.搜索旋转排序数组

1.答案
package com.sunxiansheng.arithmetic.day18;

/**
 * Description: 33. 搜索旋转排序数组
 *
 * @Author sun
 * @Create 2025/1/30 11:05
 * @Version 1.0
 */
public class t33 {

    public static int search(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return -1;
        }
        // 左闭,右闭,加等号
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            // 求中点
            int mid = left + (right - left) / 2;
            // 找到了就直接返回
            if (target == nums[mid]) {
                return mid;
            }
            // 找不到,如果左边是有序的
            if (nums[mid] >= nums[left]) {
                // 判断是否在左边
                if (target >= nums[left] && target < nums[mid]) {
                    right = mid - 1;
                } else {
                    left = mid + 1;
                }
            } else {
                // 目前是右边有序,则判断是否在右边
                if (target <= nums[right] && target > nums[mid]) {
                    left = mid + 1;
                } else {
                    right = mid - 1;
                }
            }
        }
        return -1;
    }
}
2.思路

左闭右闭加等号,求中点,如果找不到,就判断左边是不是有序的,如果左边有序,就进一步判断元素是否在左边,如果在就right = mid - 1,否则就是left = mid + 1,右边也是同理

5.在排序数组中查找元素的第一个和最后一个位置

1.答案
package com.sunxiansheng.arithmetic.day18;

/**
 * Description: 34. 在排序数组中查找元素的第一个和最后一个位置
 *
 * @Author sun
 * @Create 2025/1/30 11:23
 * @Version 1.0
 */
public class t34 {

    public int[] searchRange(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return new int[]{-1, -1};
        }
        return new int[]{getFirst(nums, target), getLast(nums, target)};
    }

    private int getFirst(int[] nums, int target) {
        // 左闭右闭,加等号
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            // 求中点
            int mid = left + (right - left) / 2;
            if (target <= nums[mid]) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        // 防止越界
        if (left < 0 || left > nums.length - 1) {
            return -1;
        }

        return nums[left] == target ? left : -1;
    }

    private int getLast(int[] nums, int target) {
        // 左闭右闭,加等号
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            // 求中点
            int mid = left + (right - left) / 2;
            if (target >= nums[mid]) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        // 防止越界
        if (right < 0 || right > nums.length - 1) {
            return -1;
        }

        return nums[right] == target ? right : -1;
    }
}
2.思路

以找到第一个元素为例,首先还是二分老套路,然后如果target小于等于mid的元素,就在左边,否则在右边,注意退出循环后要防止越界,并且最后返回的时候也要判断left下的元素是不是那个元素!

6.寻找旋转排序数组中的最小值

1.答案
package com.sunxiansheng.arithmetic.day18;

/**
 * Description: 153. 寻找旋转排序数组中的最小值
 *
 * @Author sun
 * @Create 2025/1/30 13:07
 * @Version 1.0
 */
public class t153 {

    public int findMin(int[] nums) {
        // 左闭右闭加等号
        int left = 0, right = nums.length - 1;
        int res = nums[left];
        while (left <= right) {
            // 求中点
            int mid = left + (right - left) / 2;
            // 更新最小值
            res = Math.min(res, nums[mid]);

            // 将right指向的元素当做target
            if (nums[mid] <= nums[right]) {
                right = mid - 1;
            } else  {
                left = mid + 1;
            }
        }
        return res;
    }
}
2.思路

在二分的基础上,加了一个更新最小值的操作,并且将right指向的元素当做target进行更新左右边界的操作


http://www.kler.cn/a/531168.html

相关文章:

  • LLM - 基于LM Studio本地部署DeepSeek-R1的蒸馏量化模型
  • oracle:索引(B树索引,位图索引,分区索引,主键索引,唯一索引,联合索引/组合索引,函数索引)
  • 深入理解linux中的文件(上)
  • 深度学习之“线性代数”
  • 线性回归的损失和优化02
  • Windows程序设计10:文件指针及目录的创建与删除
  • 取模与加减乘除原理,模拟实现代码及相关公式推导
  • 【线程】基于阻塞队列的生产者消费者模型
  • 【C语言篇】“三子棋”
  • kubernetes(二)
  • 对比JSON和Hessian2的序列化格式
  • 前端 | JavaScript中的reduce方法
  • 【14】WLC3504 HA配置实例
  • 【股票数据API接口49】如何获取股票实时交易数据之Python、Java等多种主流语言实例代码演示通过股票数据接口获取数据
  • 自动化构建-make/Makefile 【Linux基础开发工具】
  • 本地快速部署DeepSeek-R1模型——2025新年贺岁
  • relational DB与NoSQL DB有什么区别?该如何选型?
  • C++ Primer 迭代器
  • Unity特效插件GodFX
  • 力扣经典题目之14. 最长公共前缀
  • Alibaba开发规范_异常日志之日志规约:最佳实践与常见陷阱
  • 最新功能发布!AllData数据中台核心菜单汇总
  • Win11使用VMware提示:平台不支持虚拟化的 Intel VT-x/EPT
  • 【BUUCTF逆向题】[WUSTCTF2020]level1、[GUET-CTF2019]re
  • linux通过lvm调整分区大小
  • 【Leetcode 每日一题】81. 搜索旋转排序数组 II