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

【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;//
    }
}

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

相关文章:

  • 【002安卓开发方案调研】之Kotlin+Jetpack开发方案
  • 无人机点对点技术要点分析!
  • mayfly-go开源的一站式 Web 管理平台
  • 【el-upload】el-upload组件 - list-type=“picture“ 时,文件预览展示优化
  • strstr!!!
  • springCloud集成tdengine(原生和mapper方式) 其二 原生篇
  • 【嵌入式学习】计算机自动运行小组件
  • 基于大模型的甲状舌管囊肿全流程预测与临床方案研究报告
  • python学习笔记--实现简单的爬虫(一)
  • vlan路由间配置
  • Pytorch中的torch.utils.data.Dataset 类
  • TSL 和 SSL 是什么?它们有何关系?
  • 3.20-epoll 函数
  • 通俗易懂搞懂@RequestParam 和 @RequestBody
  • 2025年01月03日微创网络(杭州银行外包)前端面试
  • OpenCV Objdetect 模块使用指南
  • 尝试将相机采集图像流程封装成相机采图类
  • 微信小游戏:跳一跳,自动化操作
  • BlockChain.java
  • 西门子200smart之modbus_TCP(做从站与第三方设备)通讯