LeetCode——二分查找

二分查找

分类:1)找某个数;2)找左边界;3)找右边界

注意点:1)mid = left + (right - left) / 2

​ 2)if中的判断条件,目的是把数组分开,确定更小的搜索区间

1.搜索插入位置35简单

java 复制代码
class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] < target) {
                left = mid + 1;
            } else if (nums[mid] > target) {
                right = mid - 1;
            }
        }
        // if (left > nums.length) {
        //     return left + 1;
        // }
        // return left;
        return left;
    }
}

记录:数组是排序好的,从中找到目标值,返回索引。定义初始搜索区间[0, n - 1],是个闭区间,所以结束循环的条件是left <= right,计算mid,调整搜索区间:如果mid的值大于target,说明右半部分区间都大于target,就要缩小搜索区间到左半部分;如果mid的值小于target,说明左半部分区间都小于target,就要缩小搜索区间到右半部分,直到找到target返回下标或者数组中不存在target。

2. 搜索二维矩阵 74中等

java 复制代码
class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        // 循环判断target是否在某行中
        int m = matrix.length;
        int n = matrix[0].length;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] >= matrix[i][0] && matrix[i][j] <= matrix[i][n-1]) {
                    // 二分查找
                    int left = 0;
                    int right = n - 1;
                    while (left <= right) {
                        int mid = left + (right - left) / 2;
                        if (matrix[i][mid] == target) {
                            return true;
                        } else if (matrix[i][mid] > target) {
                            right = mid - 1;
                        } else if (matrix[i][mid] < target) {
                            left = mid + 1;
                        }
                    }
                } else {
                    continue;
                }
            }
        }
        // 在某行中使用二分查找
        return false;
    }
}

记录:二维有序,所以先确定要搜索的行,在某行中进行二分查找,找到target。

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

java 复制代码
class Solution {
    public int[] searchRange(int[] nums, int target) {
        // 定义二位result数组存放结果
        int[] result = new int[2];
        result[0] = -1;
        result[1] = -1;
        // if (nums.length == 0) {
        //     return result;
        // }
        // if (nums.length == 1 && nums[0] != target) {
        //     return result;
        // }
        // 同时寻找左边界和右边界,l_代表左边界,r_代表右边界
        int l_left = 0;
        int l_right = nums.length;
        int r_left = 0;
        int r_right = nums.length;
        // 左边界
        while (l_left < l_right) {
            int mid = l_left + (l_right - l_left) / 2;
            if (nums[mid] == target) {
                l_right = mid;
            } else if (nums[mid] < target) {
                l_left = mid + 1;
            } else if (nums[mid] > target) {
                l_right = mid;
            }
        }
        // 右边界
        while (r_left < r_right) {
            int mid = r_left + (r_right - r_left) / 2;
             if (nums[mid] == target) {
                r_left = mid + 1;
             } else if (nums[mid] < target) {
                r_left = mid + 1;
             } else if (nums[mid] > target) {
                r_right = mid;
             }
        }

        if (l_left < nums.length && nums[l_left] == target) {
            result[0] = l_left;
        }
        // 这里的条件一定要注意!!!
        if (r_left - 1 >= 0 && r_left - 1 < nums.length && nums[r_left - 1] == target) {
            result[1] = r_left - 1;
        }

    return result;
    }
}

记录:题目中寻找第一个和最后一个位置,相当于搜索左边界和右边界,将问题转换后按逻辑写。

4. 搜索旋转排序数组 33 中等

java 复制代码
// 思路一:排序后进行二分查找
// 思路二:找到旋转点,分成左右两部分,比较一下target和两部分的开始值,确定其中一部分进行二分查找------>最后计算一下在原nums中的下标
// 思路三:直接二分,判断两边那边有序,在顺序区间二分,如果没在,再分为有序和乱序两部分
// 思路二
// class Solution {
//     public int search(int[] nums, int target) {
//         int n = nums.length;
//         int index = 0;
//         for (int i = 1; i < n; i++) {
//             if (nums[i] <= nums[i - 1]) {
//                 index = i;
//                 break;
//             }
//         }
//         int left = 0;
//         int right = n - 1;
//         // 设个标识标记是前半部分还是后半部分
//         int flag = 0; // 0表示二分前半部分,1表示二分后半部分
//         // 判断一下二分前一部分,还是后一部分
//         if (nums[0] > target) {
//             left = index;
//             flag = 1;
//         } else {
//             if (index != 0) {
//                 right = index - 1;
//             }
//         }
//         // 二分
//         while (left <= right) {
//             int mid = left + (right - left) / 2;
//             if (nums[mid] == target) {
//                 // if (flag == 0) {
//                 //     System.out.println("111");
//                 //     return mid + (n - index);
//                 // }
//                 // return mid - index;
//                 return mid;
//             } else if (nums[mid] < target) {
//                 left = mid + 1;
//             } else if (nums[mid] > target) {
//                 right = mid - 1;
//             }
//         }
//         return -1;
//     }
// }

// 思路三
class Solution {
    public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] >= nums[left]) {
                // 主要是判断下次是选顺序区间还是乱序区间
                // 左半部分有序
                if (nums[mid] > target && target >= nums[left]) {
                    right = mid - 1;
                } else {
                    left = mid + 1;
                }
                // if (nums[left] < nums[mid] && nums[left] >= target) {
                //     left = mid + 1;
                // } else {
                //     right = mid - 1;
                // }
            } else if (nums[mid] <= nums[right]) {
                // 右半部分有序
                // if (nums[left] > target) {
                //     left = mid + 1;
                // } else {
                //     right = mid - 1;
                // }
                if (nums[mid] < target && target <= nums[right]) {
                    left = mid + 1;
                } else {
                    right = mid - 1;
                }
            }
            System.out.println("left:" + left + "--mid:" + mid);
        }
        return -1;
    }
}

5. 寻找旋转排序数组中的最小值 153 中等

java 复制代码
// 思路一:排序后第一个
// class Solution {
//     public int findMin(int[] nums) {
//         Arrays.sort(nums);
//         return nums[0];
//     }
// }

// // 思路二:本身有序,旋转是向后移一位------>找到中间点
// class Solution {
//     public int findMin(int[] nums) {
//         int n = nums.length;
//         int result = nums[0];
//         for (int i = 1; i < n; i++) {
//             if (nums[i] < nums[i-1]) {
//                 result = nums[i];
//                 break;
//             }
//         }
//         return result;
//     }
// }

// 思路三:二分查找
class Solution {
    public int findMin(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        int minValue = 5001;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[left] <= nums[mid]) {
                minValue = Math.min(minValue, nums[left]);
                left = mid + 1;
            } else {
                minValue = Math.min(minValue, nums[mid]);
                right = mid - 1;
            }
        }
        return minValue;
    }
}
相关推荐
极客先躯1 分钟前
高级java每日一道面试题-2025年3月21日-微服务篇[Nacos篇]-什么是Nacos?
java·开发语言·微服务
工业互联网专业10 分钟前
基于springboot+vue的动漫交流与推荐平台
java·vue.js·spring boot·毕业设计·源码·课程设计·动漫交流与推荐平台
雷渊12 分钟前
深入分析Spring的事务隔离级别及实现原理
java·后端·面试
Smilejudy22 分钟前
不可或缺的相邻引用
后端
惜鸟22 分钟前
Elasticsearch 的字段类型总结
后端
rebel24 分钟前
Java获取excel附件并解析解决方案
java·后端
微客鸟窝26 分钟前
Redis常用数据类型和命令
后端
熊猫片沃子28 分钟前
centos挂载数据盘
后端·centos
微客鸟窝29 分钟前
Redis配置文件解读
后端
不靠谱程序员31 分钟前
"白描APP" OCR 软件 API 逆向抓取
后端·爬虫