算法篇之二分

news2025/1/25 23:45:43

二分算法简介

特点

最简单的一种算法,也是最恶心,细节最多,最容易写出死循环的算法
时间复杂度O(logN)

如何学习

  1. 明白其中的算法原理,二分并不是只有数组有序的的时候使用,而是看是否具有二段性。
  2. 模板
    1. 朴素的二分模板(easy,有局限性)
    2. 查找左边界的二分模板
    3. 查找右边界的二分模板

b,c两种模板是万能模板,但是细节多

二分查找

image.png

题目链接:二分查找

算法思路:

image.png

代码
class Solution {
    public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        // 当left == right的时候还未判断
        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;
    }
}

朴素二分模板

image.png

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

image.png

题目链接:在排列数组中查找元素的第一个和最后一个位置

算法思路

image.png

代码
class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] result = new int[2];
        result[0] = result[1] = -1;
        if(nums.length == 0) return result;
        // 寻找区间左端点()
        int left = 0, right = nums.length - 1;
        // 1. left<=right会死循环,当left=right找到target时,进入循环还会走right=mid,一直循环下去。
        // 2. 当left==right时就是答案,不需要再判断了
        while(left < right) {
            // 如果数组是偶数要取左边元素
            // 因为取右边的元素会死循环,比如如果剩下(1,2)两个元素
            // left=1,right=2,mid=2.更新区间后,left,right,mid的值没有改变
            int mid = left + (right - left) / 2;
            // 二段性,左区间小于target,右区间大于等于target
            if(nums[mid] < target) {
                left = mid + 1; // 由于左区间都是小于target,所以left=mid+1
            }else {
                right = mid;// 由于target在右区间间,所有right不能等于mid-1
            }
        }
        if(nums[left] != target) return result;
        result[0] = left;
        // 寻找区间右端点
        left = 0;
        right = nums.length - 1;
        while(left < right) {
            // 如果数组是偶数要取右边元素
            // 因为取左边的元素会死循环,比如如果剩下(1,2)两个元素
            // left=1,right=2,mid=2.更新区间后,left,right,mid的值没有改变
            int mid = left + (right - left + 1) / 2;
            if(nums[mid] <= target) {
                left = mid; // 由于左区间都是小于等于target,所以left不能等于mid+1
            }else {
                right = mid - 1; // 由于右区间都是小于target,所以right=mid-1
            }
        }
        result[1] = left;
        return result;
    }
}

模板

image.png

搜索插入位置

image.png

题目链接:搜索插入位置

算法思路

数组是有序数组,具有二段性。可以将数组划分左右两个区间,左区间<=target,右区间>target。即可以套用求右端点模板。

代码
class Solution {
    public int searchInsert(int[] nums, int target) {
        // 利用二段性,可以划分为左区间<=target,右区间>target
        // 也可以划分为左区间<target,右区间>=target
        // 咱们这里采用查找区间右端点模板
        int left = 0, right = nums.length - 1;
        while(left < right) {
            int mid = left + (right - left + 1) / 2;
            if(nums[mid] <= target) {
                left = mid;
            }else {
                right = mid - 1;
            }
        }
        if(nums[left] < target) return left + 1;
        return left;
     }
}

X的平方根

image.png

题目链接:X的平方根

算法思路

image.png

代码:
class Solution {
    public int mySqrt(int x) {
        // x的平分根一定在0~x之间
        long left = 0, right = x;
        // 变成求mid*mid=x
        // 因为保留整数部分,可以划分为左区间<=x,右区间>x
        while(left < right) {
            // 使用long,反溢出
            long mid = left + (right - left + 1) / 2;
            if(mid * mid <= x) {
                left = mid;
            }else {
                right = mid - 1;
            }
        }
        return (int)left;
    }
}

山脉数组的峰顶索引

image.png

题目链接:山脉数组的峰顶索引

算法思路:

image.png

代码:
class Solution {
    public int peakIndexInMountainArray(int[] arr) {
        // 利用二段性,可以将区间分为小于等于峰值的左区间,小于峰值的右区间
        // 即套用求区间右端点模板
        int left = 0, right = arr.length - 1;
        while(left < right) {
            int mid = left + (right - left + 1) / 2;
            if(arr[mid] > arr[mid - 1]) {
                left = mid;
            }else {
                right = mid - 1;
            }
        }
        return left;
    }
}

寻找峰值

image.png

题目链接:寻找峰值

算法思路:

image.png
二段性:任取一个点i,与下一个点i+1会有如下两种情况

  • nums[i] > nums[i+1]:此时「左侧区域」⼀定会存在⼭峰(因为最左侧是负⽆ 穷),那么我们可以去左侧去寻找结果;
  • nums[i] < nums[i+1]:此时「右侧区域」⼀定会存在⼭峰(因为最右侧是负⽆ 穷),那么我们可以去右侧去寻找结果;
代码:
class Solution {
    public int findPeakElement(int[] nums) {
        int left = 0, right = nums.length - 1;
        while(left < right) {
            int mid = left + (right - left) / 2;
            if(nums[mid] > nums[mid + 1]) {
                right = mid;
            }else {
                left = mid + 1;
            }
        }
        return left;
    }
}

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

image.png

题目链接:寻找旋转排序数组中的最小值

算法思路:

image.png
⼆分的本质:找到⼀个判断标准,使得查找区间能够⼀分为⼆。
通过图像我们可以发现, [A,B] 区间内的点都是严格⼤于 D 点的值的, C 点的值是严格小于 D 点的值的。但是当 [C,D] 区间只有⼀个元素的时候, C 点的值是可能等于 D 点的值的。
因此,初始化左右两个指针 left , right :
然后根据 mid 的落点,我们可以这样划分下⼀次查询的区间:

  • 当 mid 在 [A,B] 区间的时候,也就是 mid 位置的值严格⼤于 D 点的值,下⼀次查询区间在 [mid + 1,right] 上;
  • 当 mid 在 [C,D] 区间的时候,也就是 mid 位置的值严格⼩于等于 D 点的值,下次查询区间在 [left,mid] 上。

当区间⻓度变成 1 的时候,就是我们要找的结果。

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

0到n-1中缺失的数字

image.png

题目链接:0到n-1中缺失的数字

算法思路:

image.png
在这个升序的数组中,我们发现:

  • 在第⼀个缺失位置的左边,数组内的元素都是与数组的下标相等的;
  • 在第⼀个缺失位置的右边,数组内的元素与数组下标是不相等的。

因此,我们可以利⽤这个「⼆段性」,来使⽤「⼆分查找」算法。

代码:
class Solution {
    public int takeAttendance(int[] records) {
        // 可以划分为左区间数值和下标相等,右区间数值和下标不相等
        int left = 0, right = records.length - 1;
        while(left < right) {
            int mid = left + (right - left) / 2;
            if(records[mid] == mid) {
                left = mid + 1;
            }else {
                right = mid;
            }
        }
        // 注意处理数组只有一个数的情况
        return records[left] == left ? left + 1 : left;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1426657.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法面试八股文『 基础知识篇 』

博客介绍 近期在准备算法面试&#xff0c;网上信息杂乱不规整&#xff0c;出于强迫症就自己整理了算法面试常出现的考题。独乐乐不如众乐乐&#xff0c;与其奖励自己&#xff0c;不如大家一起嗨。以下整理的内容可能有不足之处&#xff0c;欢迎大佬一起讨论。 PS&#xff1a;…

失物招领|基于Springboot的校园失物招领系统设计与实现(源码+数据库+文档)

校园失物招领系统目录 目录 基于Springboot的校园失物招领系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、 管理员功能实现 (1) 失物招领管理 (2) 寻物启事管理 (3) 公告管理 (4) 公告类型管理 2、用户功能实现 (1) 失物招领 (2) 寻物启事 (3) 公告 …

2024 美国大学生数学建模竞赛 美赛(C题)网球比赛趋势问题 国际大学生数学建模竞赛| 建模秘籍文章代码思路大全

铛铛&#xff01;小秘籍来咯&#xff01; 小秘籍希望大家都能轻松建模呀&#xff0c;华数杯也会持续给大家放送思路滴~ 抓紧小秘籍&#xff0c;我们出发吧~ 完整内容可以在文章末尾领取&#xff01; 问题1 • 开发一个模型&#xff0c;捕捉到比赛进行时点的流动&#xff0c;…

(2)(2.11) RFD900

文章目录 前言 1 概述 2 主要功能 3 状态LED指示灯 4 接口 5 使用Mission Planner进行配置 6 支持不同国家/地区 7 讨论论坛 前言 RFD900 无线电调制解调器是一款高功率 900Mhz ISM 波段无线电调制解调器&#xff0c;设计用于远距离串行通信。据报道&#xff0c;其通信…

2024美国大学生数学建模美赛选题建议+初步分析

总的来说&#xff0c;去年算是美赛环境题元年&#xff0c;去年的开放度是较高的&#xff0c;今年每种赛题类型相对而言平均了起来 提示&#xff1a;DS C君认为的难度&#xff1a;E<BCF<AD&#xff0c;开放度&#xff1a;DBCE<A<F。 以下为A-F题选题建议及初步分析…

C++(17.5)——list模拟实现扩展

在上篇文章中&#xff0c;实现了的大部分功能以及部分迭代器。本片文章将对剩下的功能进行补充。 1. const迭代器&#xff1a; 对于上篇文章中实现的迭代器只能使用于非类型的对象。对于类型的遍历&#xff0c;则需要额外编写类型的迭代器。例如对于下面的场景&#xff1a; …

grafana安装DevOpsProdigy KubeGraf 1.5.2

安装DevOpsProdigy KubeGraf需要安装kube-state-metrics 官方地址&#xff1a;https://github.com/kubernetes/kube-state-metrics/tree/release-2.10/examples/standard 查看k8s版本和kube-state-metrics对应版本&#xff1a; [rootmaster1 kube-state-metrics]# ll 总用量 …

25考研|660/880/1000/1800全年带刷计划

作为一个参加过两次研究生考试的老学姐&#xff0c;我觉得考研数学的难度完全取决于你自己 我自己就是一个很好的例子 21年数学题目是公认的简单&#xff0c;那一年考130的很多&#xff0c;但是我那一年只考了87分。但是22年又都说是有史以来最难的一年&#xff0c;和20年的难度…

华擎B660 主板 怎么设置打开来电自启功能?

环境&#xff1a; 华擎B660 钢铁传奇 1700 : Intel B660 问题描述&#xff1a; 华擎B660 主板 怎么设置打开来电自启功能&#xff1f; 解决方案&#xff1a; 1.前往-高级- 芯片组配置 2.往下划找到交流 /电源断电恢复 选择电源故障后的电源状态。如果选择 [关机]&#x…

《PCI Express体系结构导读》随记 —— 第II篇 第4章 PCIe总线概述(4)

接前一篇文章&#xff1a;《PCI Express体系结构导读》随记 —— 第II篇 第4章 PCIe总线概述&#xff08;3&#xff09; 4.1.2 PCIe总线使用的信号 PCIe设备使用两种电源信号供电&#xff0c;分别是Vcc与Vaux&#xff0c;其额定电压为3.3V。其中Vcc为主电源&#xff0c;PCIe设备…

免费分享一套SpringBoot+Vue药店(药房)管理系统,帅呆了~~

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue药店(药房)管理系统 &#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue药店(药房)管理系统 Java毕业设计_哔哩哔哩_bilibili【免费】SpringBootVue药店(药房)管理系统 Java毕业设计…

flutter实战之美化 container

我们来看一个代码 Column(children: [...transaction.map((e) > Card(child:Row(children: [Container(child: Text(e.amout.toString()),),Column(children: [Text(e.title),Text(e.date.toString()),],)],),)).toList()],) 看看效果 感觉很不好 我们要去美化一下contai…

[晓理紫]每日论文分享(有中文摘要,源码或项目地址)

专属领域论文订阅 关注{晓理紫|小李子}&#xff0c;每日更新论文&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持 如果你感觉对你有所帮助&#xff0c;请关注我&#xff0c;每日准时为你推送最新论文。 为了答谢各位网友的支持&#xff0c;从今日起…

pytorch_car_caring 排坑记录

pytorch_car_caring 排坑记录 任务踩坑回顾简单环境问题代码版本问题症状描述解决方法 cuda问题&#xff08;异步问题&#xff09;症状描述解决方法 任务 因为之前那个MPC代码跑出来的效果不理想&#xff0c;看了一天代码&#xff0c;大概看明白了&#xff0c;但要做改进还要有…

力扣hot100 对称二叉树 递归

Problem: 101. 对称二叉树 文章目录 思路Code 思路 &#x1f468;‍&#x1f3eb; 参考 Code 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( n ) O(n) O(n) /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* …

Pytorch从零开始实战18

Pytorch从零开始实战——人脸图像生成 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——人脸图像生成环境准备模型定义开始训练可视化总结 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c;Pytorch2.0.1cu118&#…

jmerter-01安装与界面介绍

文章目录 jmeter安装 jmeter安装 1.配置JDK环境 Jmeter到目前为止只支持java 8 2.解压JMeter安装包 就可以双击jmeter.bat 运行启动 3.运行过程中&#xff0c;不要关掉小黑窗 这个黑框不要关闭 jmeter图示

【CSS】外边距折叠(margin 塌陷)

外边距折叠(collapsing margins) 毗邻的两个或多个margin会合并成一个margin&#xff0c;叫做外边距折叠。 规则如下: 两个或多个毗邻的普通流中的块元素垂直方向上的 margin会折叠浮动元素 / inline-block元素 / 绝对定位元素 / 行内元素的margin不会和垂直方向上的其他元素…

使用Logstash将MySQL中的数据同步至Elasticsearch

目录 1 使用docker安装ELK 1.1 安装Elasticsearch 1.2 安装Kibana 1.3 安装Logstash 2 数据同步 2.1 准备MySQL表和数据 2.2 运行Logstash 2.3 测试 3 Logstash报错(踩坑)记录 3.1 记录一 3.1.1 报错信息 3.1.2 报错原因 3.1.3 解决方案 3.2 记录二 3.2.1 报错信…

深入了解C++:底层编译原理

进程的虚拟空间划分 任何编程语言&#xff0c;都会产生两样东西&#xff0c;指令和数据。 .exe程序运行的时候会从磁盘被加载到内存中&#xff0c;但是不能直接加载到物理内存中。Linux会给当前进程分配一块空间&#xff0c;比如x86 32位linux环境下会给进程分配2^32(4G)大小…