二分算法题

news2024/11/18 2:32:59

文章目录

    • 一、在排序数组中查找数字
    • 二、0~n-1中缺失的数字
    • 三、旋转数组的最小数字
    • 四、二维数组中的查找

一、在排序数组中查找数字

题目传送门
法一:暴力解
直接遍历然后计数

法二:二分法求边界
看到关键字排序数组、有序数组,一定要想到二分的方法,效率高,思路也比较简单

思路:使用二分法、找数组的左边界(left)和右边界(right),最后目标数字个数就是right-left+1
对于二分法,我们可以分别求左边界和右边界,也可以二分求左边界之后接着遍历计数,两种情况对应在真实场景下连续相等的数据一般有多长。如果经常出现很长一串连续相等的数据,就用二分法求右边界,否则容易使算法退化到O(N)。PS: 在C ++11 标准中,nums.size()的时间复杂度是Constant常数级,O(1)

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int res=0;
        int idx=getFirstIndex(nums,target);
        if(idx==-1) 
            return res;
        
        for(int i=idx;i<nums.size()&&nums[i]==target;i++)
        {
            res++;
        }
        return res;
    }

    int getFirstIndex(vector<int> & nums,int target)
    {
        int left=0;
        int right=nums.size()-1;
        int res=-1;

        while(left<=right)
        {
            int mid=(left+right)/2;

            if(nums[mid]>target)
            {
                right=mid-1;
            }
            else if(nums[mid]<target)
            {
                left=mid+1;
            }
            else
            {
                res=mid;
                right=mid-1;
            }  
        }
        return res;
    }
};

标准解法:

class Solution {
public:
    int binarySearch(vector<int>& nums, int target, bool lower) 
    {
        int left = 0, right = (int)nums.size() - 1, ans = (int)nums.size();
        while (left <= right) 
        {
            int mid = (left + right) / 2;
            if (nums[mid] > target || (lower && nums[mid] >= target)) {
                right = mid - 1;
                ans = mid;
            } else {
                left = mid + 1;
            }
        }
        return ans;
    }

    int search(vector<int>& nums, int target) 
    {
        int leftIdx = binarySearch(nums, target, true);
        int rightIdx = binarySearch(nums, target, false) - 1;
        if (leftIdx <= rightIdx && rightIdx < nums.size() && nums[leftIdx] == target && nums[rightIdx] == target) {
            return rightIdx - leftIdx + 1;
        }
        return 0;
    }
};

二、0~n-1中缺失的数字

题目传送门

思路:因为有序,所以可以看看下标是否等于数组中的对应元素
初始化: 左边界 left = 0 ,右边界 right = len(nums)−1 ;代表闭区间 [left, right] 。
循环二分: 当 left ≤ right 时循环 (即当闭区间 [left, right] 为空时跳出) ;
1、计算中点 mid = (left + right)//2 ,其中 “//” 为向下取整除法;
2、若 nums[mid] = mid ,说明mid前面的元素肯定都是完整的不少元素所以只需要继续二分右边的数组即可,则 “右子数组的首位元素” 一定在闭区间 [mid+1, right] 中,因此执行 left = mid+1;
3、若 nums[mid] != mid ,说明mid前面的元素就有少的所以只要继续二分左边的数组即可,则 “左子数组的末位元素” 一定在闭区间 [left, mid−1] 中,因此执行 right = mid−1;
4返回值: 跳出时,变量 i 和 j 分别指向 “右子数组的首元素” 和 “左子数组的末元素” 。因此返回 i 即可。

在这里插入图片描述

class Solution {
public:
    int missingNumber(vector<int>& nums) {
       
       int left=0,right=nums.size()-1;
       while(left<=right)
       {
           int mid=(left+right)/2;
           if(nums[mid]==mid)
           {
               left=mid+1;
           }
           else{
               right=mid-1;
           }
       }
       return left;
    }
};

三、旋转数组的最小数字

题目传送门
题目分析
旋转数组:把一个有重复数字的有序数组,末位一部分移动到头部,这就叫做旋转数组。在这里插入图片描述

我们的目标就是找到这个分界点!
在这里插入图片描述
法一:暴力
分界点右边的第一个数字就是我们要找的最小数字
在这里插入图片描述
其实可以类比数学中的找极点
在这里插入图片描述

class Solution {
public:
    int minArray(vector<int>& numbers) {
		// 注意i=0开始,要越界,特殊处理一下,从1开始可以避免
        for(int i=1;i<numbers.size();i++)
        {
            if(numbers[i-1]>numbers[i])
            return numbers[i];
        }
        return numbers[0];
    }
};

法二:二分法
题目说了,可能存在重复的数字
在这里插入图片描述
在这里插入图片描述
---------------------===
在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    int minArray(vector<int>& numbers) {
        int left=0;
        int right=numbers.size()-1;
        
        if(right==0) return numbers[0];
        
        while(left<right)
        {
            int mid=left+(right-left)/2;
            if(numbers[mid]>numbers[right])
                left=mid+1;
            else if(numbers[mid]<numbers[right])
                right=mid;
            else
                right--;
        }
        return numbers[left];
    }
};

四、二维数组中的查找

TP
法一:暴力
直接遍历矩阵,判断有没有target

class Solution {
public:
    bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
        for(auto row: matrix)
        {
            for(auto e: row)
            {
                if(e==target)
                    return true;
            }
        }
        return false;
    }
};

时间复杂度:O(MN)
空间复杂度:O(1)

法二:行二分
对二维数组每一行,进行二分查找

class Solution {
public:
    bool findNumberIn2DArray(vector<vector<int>>& matrix, int t) {
        if (matrix.size() == 0 || matrix[0].size() == 0) 
            return false;
        int n = matrix.size(), m = matrix[0].size();
        int l = 0, r = 0, mid = 0;
        for (int i = 0; i < n; i ++) {
            l = 0;
            r = m - 1;
            while (l <= r) {
                mid = l + (r - l) / 2;
                if (matrix[i][mid] == t) return true;
                if (matrix[i][mid] < t) l = mid + 1;
                if (matrix[i][mid] > t) r = mid - 1;
            }  
        }
        return false;
    }
};

时间复杂度:O(MlogN)
空间复杂度:O(1)

法三:Z字形查找
在这里插入图片描述

class Solution
{
public:
	bool findNumberIn2DArray(vector<vector<int>> &matrix, int target)
	{
		int i = matrix.size() - 1; // 行
		int j = 0;				   // 列
		if (matrix.size() == 0 || matrix[0].size() == 0)
			return false;
		while (i >= 0 && j <= matrix[0].size() - 1)
		{
			if (matrix[i][j] > target)
				i--;
			else if (matrix[i][j] < target)
				j++;
			else
				return true;
		}
		return false;
	}
};

时间复杂度:O(M+N)
M,N为矩阵的行数和列数
空间复杂度:O(1)

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

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

相关文章

Nacos2.x+Nginx集群配置

一、配置 nacos 集群 注意&#xff1a;需要先配置好 nacos 连接本地数据库 1、拷贝三份 nacos 2、修改配置文件&#xff08;cluster.conf&#xff09; 修改启动端口&#xff1a; nacos1&#xff1a;8818 nacos2&#xff1a;8828 nacos3&#xff1a;8838 当nacos客户端升级为…

Linux-0.11 kernel目录fork.c详解

Linux-0.11 kernel目录fork.c详解 fork.c中主要实现内核对于创建新的进程的行为。其中copy_process是其最核心的函数。 copy_process int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,long ebx,long ecx,long edx,long fs,long es,long ds,long eip,…

如何使用Coercer强制Windows Server认证任意主机

关于Coercer Coercer是一款功能强大的Python脚本&#xff0c;该工具可以通过九种不同的方法来强制让一台Windows Server认证任意主机。 功能介绍 1、自动检测远程设备的开放SMP管道&#xff1b; 2、一一调用存在安全漏洞的RPC功能来强制一台Windows Server认证任意主机&#…

字节二面,原来是我对自动化测试的理解太浅薄了..

如何使用Python实现自动化测试 如果你入职一家新的公司&#xff0c;领导让你开展自动化测试&#xff0c;作为一个新人&#xff0c;你肯定会手忙脚乱&#xff0c;你会如何落地自动化测试呢&#xff1f;资深测试架构师沉醉将告诉你如何落地自动kan化测试&#xff0c;本次话题主要…

什么是链表,如何实现?(单链表篇)

欢迎来到 Claffic 的博客 &#x1f49e;&#x1f49e;&#x1f49e; “仅仅活着是不够的&#xff0c;还需要有阳光&#xff0c;自由和花的芬芳。” 前言&#xff1a; 在日常使用的网站和软件中&#xff0c;列表属于最常见的一种东西了&#xff0c;其实现形式有顺序表&#xff0…

工具篇4.5数据可视化工具大全

1.1 Flourish 数据可视化不仅是一项技术&#xff0c;也是一门艺术。当然&#xff0c;数据可视化的工具也非常多&#xff0c;仅 Python 就有 matplotlib、plotly、seaborn、bokeh 等多种可视化库&#xff0c;我们可以根据自己的需要进行选择。但不是所有的人都擅长写代码完成数…

“一网统管”视频融合平台EasyCVR页面tab切换细节优化

EasyCVR视频融合平台基于云边端协同架构&#xff0c;能支持海量视频的轻量化接入与汇聚管理&#xff0c;借助大数据分析的决策判断&#xff0c;为网络摄像头、网络存储设备、智能终端、无人机、车载设备、移动执法仪、视频监控平台等提供一体化的视频接入、分发、存储、处理等能…

魔兽世界全版本GM命令全集

命令:.levelup 79 (升级数1-79) .modify money 999999999 增加金币.modify hp 9999999 9999999 增加被选择人物的血量 .modify mana 9999999 9999999 增加被选择人物的蓝量 .modify speed 30 加速人物跑步.modify speed 1 还原人物跑步.modify aspeed 1 还原人物游泳.gm fly on…

RuoYi-Bootstrap多模块版本使用过程中遇到的问题

1、设置复杂表头 最终效果见下图&#xff1a; 实现过程中错误&#xff1a; 页面报错&#xff0c;visible未定义&#xff0c;最开始以为是columns内的visible属性的问题&#xff0c;但是注释掉之后还是报同样的错误&#xff08;见下图&#xff09; 最开始的时候所有的列没有增加…

【架构师】零基础到精通——路由发现体系

博客昵称&#xff1a;架构师Cool 最喜欢的座右铭&#xff1a;一以贯之的努力&#xff0c;不得懈怠的人生。 作者简介&#xff1a;一名Coder&#xff0c;软件设计师/鸿蒙高级工程师认证&#xff0c;在备战高级架构师/系统分析师&#xff0c;欢迎关注小弟&#xff01; 博主小留言…

啃下这350+软件测试工程师面试题,4面阿里测试岗,总算顺利拿到 offer

下边是我根据工作这几年来的面试经验&#xff0c;加上之前收集的资料&#xff0c;整理出来350道软件测试工程师常考的面试题。字节跳动、阿里、腾讯、百度、快手、美团等大厂常考的面试题&#xff0c;在文章里面都有提到。 虽然这篇文章很长&#xff0c;但是绝对值得你点击一下…

JavaScript高级程序设计读书分享之8章——8.1理解对象

JavaScript高级程序设计(第4版)读书分享笔记记录 适用于刚入门前端的同志 创建自定义对象的通常方式是创建 Object 的一个新实例&#xff0c;然后再给它添加属性和方法。 let person new Object() person.name Tom person.age 18 person.sayName function(){//示 this.name…

MySQL运维篇之主从复制

02、主从复制 2.1、概述 主从复制是指将主数据库的DDL和DML操作通过二进制日志传到从库服务器中&#xff0c;然后在从库上对这些日志重新执行&#xff08;也叫重做&#xff09;&#xff0c;从而使得从库和主库的数据保持同步。 MySQL支持一台主库同时向多台从库进行复制&…

Vue+ElementUI+SpringBoot项目配合分页插件快速实现分页(简单暴力)

首先需要在项目中引入Element-UI的组件库&#xff0c;使用以下命令&#xff0c;不会引入的请自行百度。 npm i element-ui -S Element官网地址&#xff1a;https://element.eleme.cn/#/zh-CN/component/changelog 去Element-UI官网组件库找到合适的分页插件&#xff0c;并把他引…

HashMap的7种遍历方式

目录1.JDK 8 之前的遍历1.1 EntrySet 遍历1.2 KeySet 遍历1.3 EntrySet 迭代器遍历1.4 KeySet 迭代器遍历2.JDK 8 之后的遍历2.1 Lambda 遍历2.2 Stream 单线程遍历2.3 Stream 多线程遍历3.总结1.JDK 8 之前的遍历 1.1 EntrySet 遍历 public static void main(String[] args) …

高压功率放大器在径向驻波型超声波电机研究中的应用

实验名称&#xff1a;大力矩径向驻波型超声波电机有限元分析与实验研究研究方向&#xff1a;超声电机测试目的&#xff1a;提出了一种大力矩径向驻波型超声波电机&#xff0c;在实现电机大力矩输出的同时保持结构紧凑的特点。首先设计并分析了电机的结构和工作原理&#xff0c;…

Biomod2 (上):物种分布模型预备知识总结

Biomod11.栅格数据处理1.1 读取一个栅格图片1.2 计算数据间的相关系数1.3 生成多波段的栅格图像1.4 修改变量名称1.4.1 计算多个变量之间的相关性2. 矢量数据处理2.1 提取矢量数据2.2 数据掩膜2.2 栅格计算2.3 拓展插件的使用3. 图表绘制3.1 遥感影像绘制3.2 柱状图分析图绘制3…

C语言循环控制语句Break,goto,continue语句讲解

循环控制语句改变你代码的执行顺序。通过它你可以实现代码的跳转。 C 语言中 break 语句有以下两种用法&#xff1a; 当 break 语句出现在一个循环内时&#xff0c;循环会立即终止&#xff0c;且程序流将继续执行紧接着循环的下一条语句。 它可用于终止 switch 语句中的一个 …

【日志框架-笔记】深入浅出 Log4j,理论-源码-配置

log4j一、log4j 的概述及其入门程序入门程序二、日志输出的需要及PatternLayout类源码分析日志输出的需要PatternLayout类的源码分析三、Log4j 占位符的具体含义四、Log4j 配置文件实操如何对配置文件进行解析的&#xff1f;(LogManager的静态代码块&#xff09;实操五、自定义…

ClickHouse的架构与基本概念

一、ClickHouse的定义 ClickHouse是一个完全的列式分布式数据库管理系统(DBMS)&#xff0c;允许在运行时创建表和数据库&#xff0c;加载数据和运行查询&#xff0c;而无需重新配置和重新启动服务器&#xff0c;支持线性扩展&#xff0c;简单方便&#xff0c;高可靠性&#xf…