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

【leetcode题解】二分算法

 

目录

 

二分查找

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

总结二分模板

x 的平方根

搜索插入位置

山脉数组的峰顶索引

寻找峰值

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

0~n-1中缺失的数字


二分查找

二分查找算法

适用于数组有序的时候(×)

模板:

1. 朴素的二分模板 (easy->局限)

2. 查找左边界的二分模板 (万能,细节多)

3. 查找右边界的二分模板 (万能,细节多)

朴素二分模板: 

while(left<=right){
    int mid=left+(right-left)/2;
    if(...) left=mid+1;
    else if(...) right=mid-1;
    else return ...;
}

704. 二分查找 - 力扣(LeetCode)

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

查找区间左端点细节处理

1. 循环条件:left=right的时候,就是最终结果,无需判断;如果判断就会死循环

2. 求中点的操作:Ⅰ.left+(right-left)/2 Ⅱ.left+(right-left+1)/2;(死循环)

查找区间右端点细节处理

1. 循环条件:left=right的时候,就是最终结果,无需判断;如果判断就会死循环

2. 求中点的操作:Ⅰ.left+(right-left)/2 (死循环)Ⅱ.left+(right-left+1)/2;

总结模板:

查找区间左端点的模板

while(left<right){

        int mid=left+(right-left)/2;

        if(...) left=mid+1;

        else right=mid;

}

查找区间右端点的模板

while(left<right){

        int mid=left+(right-left+1)/2;

        if(...) left=mid;

        else right=mid-1;

}

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

34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)

解法一:暴力查找

解法二:朴素二分

查找区间左端点解题思路

x<t时left=mid+1

x≥t时right=mid

查找区间左端点细节处理

1. 循环条件为left<right,而不是left≤right(left=right的时候,就是最终结果,无需判断,若判断,则死循环)

2. 求中点的操作:left+(right-left)/2若使用left+(right-left+1)/2则死循环

 查找区间右端点解题思路

x<t时left=mid

x≥t时right=mid-1

查找区间右端点细节处理

1. 循环条件为left<right,而不是left≤right(left=right的时候,就是最终结果,无需判断,若判断,则死循环)

2. 求中点的操作:left+(right-left+1)/2若使用left+(right-left)/2则死循环

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] ret = new int[2];
        ret[0] = ret[1] = -1;
        if (nums.length == 0)
            return ret;
        int left = 0, right = nums.length - 1, mid = 0;
        while (left < right) {
            mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        if (nums[left] != target)
            return ret;
        else
            ret[0] = left;
        right = nums.length - 1;
        while (left < right) {
            mid = left + (right - left + 1) / 2;
            if (nums[mid] <= target) {
                left = mid;
            } else {
                right = mid - 1;
            }
        }
        if (nums[left] != target)
            return ret;
        else
            ret[1] = left;
        return ret;
    }
}
总结二分模板
//查找区间左端点的模板:
while(left<right){
    int mid=left+(right-left)/2;
    if(...) left=mid+1;
    else right=mid;
}
//查找区间右端点的模板:
while(left<right){
    int mid=left+(right-left+1)/2;
    if(...) left=mid;
    else right=mid-1;
}
x 的平方根

69. x 的平方根 - 力扣(LeetCode)

解题思路

mid*mid≤x时left=mid

mid*mid>x时right=mid-1

class Solution {
    public int mySqrt(int x) {
        long left = 0, right = x;
        while (left < right) {
            long mid = left + (right - left + 1) / 2;
            if (mid * mid <= x)
                left = mid;
            else
                right = mid - 1;
        }
        return (int) left;
    }
}
搜索插入位置

35. 搜索插入位置 - 力扣(LeetCode)

class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0, right = nums.length - 1, mid = 0;
        if (nums[left] > target)
            return 0;
        if (nums[right] < target)
            return nums.length;
        while (left < right) {
            mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left;
    }
}
山脉数组的峰顶索引

852. 山脉数组的峰顶索引 - 力扣(LeetCode)

解法一:暴力枚举

解法二:二分查找算法(符合二段性,尽管不是有序数组)

arr[mid]>arr[mid-1]时,left=mid

arr[mid]<arr[mid-1]时,right=mid-1

class Solution {
    public int peakIndexInMountainArray(int[] arr) {
        int left = 1, right = arr.length - 2;// 第一个元素和最后一个元素绝对不会是峰顶
        int mid = 0;
        while (left < right) {
            mid = left + (right - left + 1) / 2;// 后面有-1,此处+1
            if (arr[mid] > arr[mid - 1])
                left = mid;
            else if (arr[mid] < arr[mid - 1])
                right = mid - 1;
            else
                break;
        }
        return left;//
    }
}
寻找峰值

162. 寻找峰值 - 力扣(LeetCode)

解法一:暴力解法(从第一个位置开始,一直向后走,分情况讨论)

解法二:二分查找

arr[mid]>arr[mid+1]时,right=mid

arr[mid]<arr[mid+1]时,left=mid+1

class Solution {
    public int findPeakElement(int[] nums) {
        int left = 0, right = nums.length - 1, mid = 0;
        while (left < right) {
            mid = left + (right - left) / 2;
            if (nums[mid] < nums[mid + 1])
                left = mid + 1;
            else if (nums[mid] > nums[mid + 1])
                right = mid;
            else
                break;
        }
        return left;//
    }
}
寻找旋转排序数组中的最小值

153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode)

解法一:暴力查找最小值 O(n)

解法二:二分查找算法(二段性)

参考D点:A~B段:nums[i]>nums[n-1];C~D段:nums[i]<=nums[n-1];(D点下标为n-1)

A~B:nums[mid]>nums[n-1]时left=mid+1;

C~D:nums[mid]<=nums[n-1]时right=mid.

疑问:选择A点作为参照点是否可以?可以,但需要考虑边界情况

class Solution {
    public int findMin(int[] nums) {
        int left = 0, right = nums.length - 1, mid = 0;
        int n = nums.length;
        while (left < right) {
            mid = left + (right - left) / 2;
            if (nums[mid] > nums[n - 1])
                left = mid + 1;
            else
                right = mid;
        }
        return nums[left];//
    }
}
0~n-1中缺失的数字

LCR 173. 点名 - 力扣(LeetCode)

解法一:哈希表

解法二:直接遍历找结果

解法三:位运算(异或:相同为零,相异为一)

解法四:高斯求和方式(数学方法)

以上解法时间复杂度均为O(n)

更优解法:二分

左区间:nums[mid]==mid时:left=mid+1;

右区间:nums[mid]! =mid时:right=mid.

细节

[0,1,2,3]

 0,1,2,3

class Solution {
    public int takeAttendance(int[] records) {
        int n = records.length;
        int left = 0, right = n - 1, mid = 0;
        if (records[n - 1] == n - 1)// 边界情况
            return n;
        while (left < right) {
            mid = left + (right - left) / 2;
            if (records[mid] == mid)
                left = mid + 1;
            else
                right = mid;
        }
        return left;//
    }
}

相关文章:

  • Spring6:8 资源操作-Resources
  • 排序算法总结
  • Spring的IOC
  • 回溯算法经典题目
  • 2025年03月18日柯莱特(外包宁德)一面前端面试
  • spring boot 拦截器
  • Spring Boot 集成 Elasticsearch怎样在不启动es的情况下正常启动服务
  • 什么是API❓
  • 语法: erase_program_eeprom(address)
  • NR SRS Configuration
  • C语言基础系列【27】typedef
  • AF3 quat_to_rot函数解读
  • 线性筛和欧拉函数
  • mysql实例2
  • AF3 rot_to_quat函数解读
  • 群体智能优化算法-蚁狮优化算法(Ant Lion Optimizer, ALO,含Matlab源代码)
  • 【愚公系列】《高效使用DeepSeek》024-儿童教育
  • 2025:sql注入详细介绍
  • 并发和并行、同步和异步、进程和线程的关系
  • 【MySQL篇】索引特性
  • 乌克兰议会批准美乌矿产协议
  • 马新民卸任外交部条约法律司司长
  • 2025上海科技节将于5月17日开幕,拟设6大板块专题活动
  • 国务院安委会办公室印发通知:坚决防范遏制重特大事故发生
  • 数据中心业务今年预增50%,丹佛斯:中国是全球最重要的市场
  • 万里云端遇见上博--搭乘“上博号”主题飞机体验记