力扣hot100-->二分查找

目录

二分查找

1. 33. 搜索旋转排序数组

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

3. 240. 搜索二维矩阵 II

3. 287. 寻找重复数


二分查找

1. 33. 搜索旋转排序数组

中等

整数数组 nums 按升序排列,数组中的值 互不相同 。

在传递给函数之前,nums 在预先未知的某个下标 k0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

示例 1:

输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4

示例 2:

输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1

示例 3:

输入:nums = [1], target = 0
输出:-1

提示:

  • 1 <= nums.length <= 5000
  • -104 <= nums[i] <= 104
  • nums 中的每个值都 独一无二
  • 题目数据保证 nums 在预先未知的某个下标上进行了旋转
  • -104 <= target <= 104

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left{}, right = nums.size() - 1; // 左右边界初始化

        while (left <= right) {             // 当左边界小于等于右边界时继续循环
            int mid = (left + right) / 2;   // 计算中间位置

            if (nums[mid] == target) {      // 如果找到目标值,返回索引
                return mid;
            }
            // 判断左半部分是否有序
            else if (nums[mid] >= nums[left]) {
                // 如果目标值在左半部分范围内,缩小右边界
                if (target <= nums[mid] && target >= nums[left]) {
                    right = mid - 1;
                }
                // 否则目标值在右半部分,缩小左边界
                else {
                    left = mid + 1;
                }
            }
            // 如果右半部分是有序的
            else {
                // 如果目标值在右半部分范围内,缩小左边界
                if (target >= nums[mid] && target <= nums[right]) {
                    left = mid + 1;
                }
                // 否则目标值在左半部分,缩小右边界
                else {
                    right = mid - 1;
                }
            }
        }

        return -1; // 如果未找到目标值,返回 -1
    }
};
 

解释:

在旋转排序数组中,判断左右边界是否有序的作用是:

  1. 确定目标值可能在哪一部分。
  2. 依据部分有序性,快速缩小查找范围。
  3. 使二分查找在部分有序的条件下仍然有效。

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

中等

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

示例 1:

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例 2:

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

示例 3:

输入:nums = [], target = 0
输出:[-1,-1]

提示:

  • 0 <= nums.length <= 105
  • -109 <= nums[i] <= 109
  • nums 是一个非递减数组
  • -109 <= target <= 109

方法一:

// 二分查找
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        // 先找数组中第一个不小于target的元素
        auto left = lower_bound(nums.begin(),nums.end(),target);
        // 找数组中大于目标值的第一个元素
        auto right = upper_bound(nums.begin(),nums.end(),target);
        if(left == right) return {-1,-1};

        return {(int)(left-nums.begin()),(int)(right-nums.begin() -1)};
    }
};
 

解释:

代码解析

  1. lower_boundupper_bound 的作用

    • std::lower_bound(nums.begin(), nums.end(), target)
      • 返回指向数组中第一个 大于或等于 target 的元素的迭代器。
    • std::upper_bound(nums.begin(), nums.end(), target)
      • 返回指向数组中第一个 大于 target 的元素的迭代器。
    • 如果目标值不在数组中,lower_boundupper_bound 会返回相同的迭代器指向某个位置,因此可以用它们的比较来判断目标值是否存在。
  2. 处理目标值不在数组中的情况

    • 如果 lower_boundupper_bound 的返回值相同,说明目标值在数组中不存在,直接返回 {-1, -1}

为什么需要减去 nums.begin()

在 STL 中,lower_boundupper_bound 返回的不是数组的索引,而是指向数组元素的迭代器。如果需要将迭代器转换为整数索引,就需要计算该迭代器与起始迭代器 (nums.begin()) 之间的距离。

方法二:

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        // 初始化结果为 {-1, -1},表示未找到目标值的起始和结束位置
        vector<int> result = {-1, -1};

        // 初始化左右指针,l 指向数组的起始位置,r 指向数组的末尾位置
        int l = 0, r = nums.size() - 1;

        // 开始二分查找,循环条件是左指针小于等于右指针
        while (l <= r) {
            // 计算中间位置,防止整型溢出
            int mid = l + (r - l) / 2;

            // 如果中间值小于目标值,说明目标值在右半部分,移动左指针
            if (nums[mid] < target)
                l = mid + 1;

            // 如果中间值大于目标值,说明目标值在左半部分,移动右指针
            else if (nums[mid] > target)
                r = mid - 1;

            // 如果左边界的值小于目标值,尝试向右收缩左边界
            else if (nums[l] < target)
                l++;

            // 如果右边界的值大于目标值,尝试向左收缩右边界
            else if (nums[r] > target)
                r--;

            // 如果当前左右指针的值都等于目标值,找到范围
            else {
                result[0] = l; // 起始位置为左指针的位置
                result[1] = r; // 结束位置为右指针的位置
                return result; // 直接返回结果
            }
        }

        // 如果循环结束仍未找到目标值,返回初始的 {-1, -1}
        return result;
    }
};

3. 240. 搜索二维矩阵 II

中等

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:

  • 每行的元素从左到右升序排列。
  • 每列的元素从上到下升序排列。

示例 1:

输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5
输出:true

示例 2:

输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 20
输出:false

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= n, m <= 300
  • -109 <= matrix[i][j] <= 109
  • 每行的所有元素从左到右升序排列
  • 每列的所有元素从上到下升序排列
  • -109 <= target <= 109

方法一:

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int rows = matrix.size();          // 矩阵的行数
        int cols = matrix[0].size();       // 矩阵的列数

        // 起始点:右上角
        int rowIndex = 0, colIndex = cols - 1;
        while (rowIndex < rows && colIndex >= 0) {
            if (target > matrix[rowIndex][colIndex]) 
                rowIndex++;                // 目标值更大,向下移动
            else if (target < matrix[rowIndex][colIndex]) 
                colIndex--;                // 目标值更小,向左移动
            else 
                return true;               // 找到目标值
        }
        return false;                      // 未找到目标值
    }
}; 

方法二:

// 二分查找
class Solution {
public:
    // 函数声明,用于在矩阵中搜索目标值
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        // 获取矩阵的行数和列数
        int m = matrix.size(), n = matrix[0].size();

        // 遍历每一行
        for(int i{}; i < m; ++i) {
            // 在当前行中使用lower_bound函数查找第一个不小于target的元素
            // lower_bound是STL中的算法,用于在已排序的序列中查找第一个不小于给定值的元素
            auto iter = lower_bound(matrix[i].begin(), matrix[i].end(), target);

            // 如果找到了且该元素等于目标值,则返回true
            if(iter != matrix[i].end() && *iter == target) return true;
        }
        // 如果遍历完所有行都没有找到目标值,则返回false
        return false;
    }
};

3. 287. 寻找重复数

中等

给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。

假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。

你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。

示例 1:

输入:nums = [1,3,4,2,2]
输出:2

示例 2:

输入:nums = [3,1,3,4,2]
输出:3

示例 3 :

输入:nums = [3,3,3,3,3]
输出:3

提示:

  • 1 <= n <= 105
  • nums.length == n + 1
  • 1 <= nums[i] <= n
  • nums 中 只有一个整数 出现 两次或多次 ,其余整数均只出现 一次

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int n = nums.size(); // 获取数组的长度
        int slow = 0, fast = 0; // 初始化两个指针,slow和fast,都指向数组的起始位置

        // 第一个循环:使用快慢指针找到相遇点,即环的某个节点
        do {
            slow = nums[slow]; // 慢指针向前移动一步
            fast = nums[nums[fast]]; // 快指针向前移动两步
        } while (slow != fast); // 如果两个指针相遇,则跳出循环

        // 重置慢指针到数组的起始位置
        slow = 0;
        // 第二个循环:再次使用快慢指针找到环的入口,即重复的元素
        while (slow != fast) {
            slow = nums[slow]; // 两个指针都从相遇点和起始位置向前移动一步
            fast = nums[fast];
        }

        // 返回找到的重复元素的值
        return slow;
    }
};

解释: 

  1. 初始化

    • slow 和 fast 都从索引 0 开始。
    • nums = [1,3,4,2,2]
  2. 第一次循环

    • slow = nums[0] = 1(索引 0 指向 1
    • fast = nums[nums[0]] = nums[1] = 3(索引 1 指向 3
    • slow = nums[1] = 3(索引 1 指向 3
    • fast = nums[nums[1]] = nums[3] = 2(索引 3 指向 2
    • slow = nums[3] = 2(索引 3 指向 2
    • fast = nums[nums[3]] = nums[2] = 4(索引 2 指向 4
    • slow = nums[2] = 4(索引 2 指向 4
    • fast = nums[nums[2]] = nums[4] = 2(索引 4 指向 2
    • 现在 slow 和 fast 在索引 2 相遇。
  3. 重置 slow

    • 将 slow 重置到索引 0
  4. 第二次循环

    • slow = nums[0] = 1(索引 0 指向 1
    • fast = nums[2] = 4(索引 2 指向 4
    • slow = nums[1] = 3(索引 1 指向 3
    • fast = nums[4] = 2(索引 4 指向 2
    • slow = nums[3] = 2(索引 3 指向 2
    • 现在 slow 和 fast 在索引 2 相遇。

由于 slowfast 在索引 2 相遇,数组中的重复元素是 nums[2] = 2。因此,输出是 2

4. 35. 搜索插入位置

简单

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

示例 1:

输入: nums = [1,3,5,6], target = 5
输出: 2

示例 2:

输入: nums = [1,3,5,6], target = 2
输出: 1

示例 3:

输入: nums = [1,3,5,6], target = 7
输出: 4

提示:

  • 1 <= nums.length <= 104
  • -104 <= nums[i] <= 104
  • nums 为 无重复元素 的 升序 排列数组
  • -104 <= target <= 104

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left = 0; // 初始化左指针为数组的开始
        int n = nums.size(); // 获取数组的长度
        int right = n - 1; // 初始化右指针为数组的末尾
        while (left <= right) { // 当左指针不大于右指针时,继续循环
            int middle = (left + right) / 2; // 计算中间位置的索引
            if (nums[middle] < target) { // 如果中间元素小于目标值
                left = middle + 1; // 调整左指针到中间位置的右侧
            } else if (nums[middle] > target) { // 如果中间元素大于目标值
                right = middle - 1; // 调整右指针到中间位置的左侧
            } else { // 如果中间元素等于目标值
                return middle; // 返回中间位置的索引,因为找到了目标值
            }
        }

        // 如果循环结束,说明目标值不在数组中,返回right + 1作为插入位置
        return right + 1;
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

http自动发送请求工具(自动化测试http请求)

点击下载《http自动发送请求工具(自动化测试http请求)》 前言 在现代软件开发过程中&#xff0c;HTTP 请求的自动化测试是确保应用程序稳定性和可靠性的关键环节。为了满足这一需求&#xff0c;我开发了一款功能强大且易于使用的自动化 HTTP 请求发送工具。该工具基于 C# 开发…

蓝队技能-应急响应篇日志自动采集日志自动查看日志自动化分析Web安全内网攻防工具项目

知识点&#xff1a; 1、应急响应-系统日志收集-项目工具 2、应急响应-系统日志查看-项目工具 3、应急响应-日志自动分析-项目工具 演示案例-蓝队技能-工具项目-自动日志采集&自动日志查看&自动日志分析 系统日志自动采集-观星应急工具(Windows系统日志) SglabIr_Co…

Jenkins修改LOGO

重启看的LOGO和登录页面左上角的LOGO 进入LOGO存在的目录 [roottest-server01 svgs]# pwd /opt/jenkins_data/war/images/svgs [roottest-server01 svgs]# ll logo.svg -rw-r--r-- 1 jenkins jenkins 29819 Oct 21 10:58 logo.svg #jenkins_data目录是我挂载到了/opt目录&…

k8s-NetworkPolicy

NetworkPolicy 是k8s中的网络策略可以限制pod以及namespace之间的访问流量 演示一下名称空间之间基于端口的访问限制 官方对networkpolicy的介绍 官方网址&#xff1a; 网络策略 |Kubernetes &#xff08;简体中文&#xff09; 一&#xff1a;创建NetworkPolicy vim…

【算法一周目】滑动窗口(1)

目录 长度最小的子数组 解题思路 代码实现 无重复字符的最大字串 解题思路 代码实现 最大连续1的个数l l l 解题思路 代码实现 将x减到0的最小操作数 解题思路 代码实现 长度最小的子数组 题目链接&#xff1a;209. 长度最小的子数组题目描述&#xff1a; 给定一个…

Methode Electronics EDI 需求分析

Methode Electronics 是一家总部位于美国的全球性技术公司&#xff0c;专注于设计和制造用于多个行业的电子和电气组件&#xff0c;产品涵盖汽车、工业、电信、医疗设备以及消费电子等多个领域&#xff0c;提供创新的解决方案。 填写Methode_EDI_Parameters_Template Methode_…

【K8S系列】Kubernetes集群资源管理与调度 深度分析

在现代微服务架构中&#xff0c;Kubernetes&#xff08;K8s&#xff09;作为容器编排平台&#xff0c;提供了强大的资源管理和调度能力。然而&#xff0c;随着应用规模的扩大和复杂性增加&#xff0c;如何高效地管理和调度集群资源成为一个关键挑战。本文将深入探讨 Kubernetes…

HarmonyOS鸿蒙系统上File文件常用操作

HarmonyOS鸿蒙系统上&#xff0c;file文件常用操作记录 1.创建文件 createFile(fileName: string, content: string): string {// 获取应用文件路径let context getContext(this) as common.UIAbilityContext;let filesDirPath context.filesDir / fileName;// 新建并打开…

【SpringMVC - 1】基本介绍+快速入门+图文解析SpringMVC执行流程

目录 1.Spring MVC的基本介绍 2.大致分析SpringMVC工作流程 3.SpringMVC的快速入门 首先大家先自行配置一个Tomcat 文件的配置 配置 WEB-INF/web.xml 创建web/login.jsp 创建com.ygd.web.UserServlet控制类 创建src下的applicationContext.xml文件 重点的注意事项和说明…

DTH11传感器温度湿度+esp8266+阿里云+小程序

arduino在之前灯的基础上再添加两个库 Adafruit_Sensor&#xff0c;#include “DHT.h” 代码如下 #include <ESP8266WiFi.h> // 引入Arduino ESP8266核心库 #include <ArduinoJson.h> // 引入JSON处理库 #include <Ticker.h> // 引入定时库 #inclu…

【汇编语言】转移指令的原理(三) —— 汇编跳转指南:jcxz、loop与位移的深度解读

文章目录 前言1. jcxz 指令1.1 什么是jcxz指令1.2 如何操作 2. loop 指令2.1 什么是loop指令2.2 如何操作 3. 根据位移进行转移的意义3.1 为什么&#xff1f;3.2 举例说明 4. 编译器对转移位移超界的检测结语 前言 &#x1f4cc; 汇编语言是很多相关课程&#xff08;如数据结构…

mac安装appuim

要在macOS上安装Appium&#xff0c;这是一个自动化测试框架&#xff0c;可以用来对移动应用进行测试&#xff08;支持iOS和Android应用&#xff09;。为了安装Appium和其依赖的环境&#xff0c;你需要做一些准备工作。以下是详细的安装步骤&#xff1a; 前提条件 1、macOS系统…

【WSL+Kali】进行系统升级时在 Setting up libc6:amd64 (2.37-15) ... 卡住不动

问题描述 当尝试执行以下命令进行系统升级时&#xff1a; sudo apt upgrade升级进程在以下步骤中卡住不动&#xff1a; Setting up libc6:amd64 (2.37-15) ...重启系统后&#xff0c;该问题仍然存在&#xff0c;如下图所示&#xff1a; 原因分析 apt命令是一个用于处理包的…

DevOps工程技术价值流:加速业务价值流的落地实践与深度赋能

DevOps的兴起&#xff0c;得益于敏捷软件开发的普及与IT基础设施代码化管理的革新。敏捷宣言虽已解决了研发流程中的诸多挑战&#xff0c;但代码开发仅是漫长价值链的一环&#xff0c;开发前后的诸多问题仍亟待解决。与此同时&#xff0c;虚拟化和云计算技术的飞跃&#xff0c;…

微深节能 平板小车运动监测与控制系统 格雷母线

微深节能的平板小车运动监测与控制系统中的格雷母线&#xff0c;是一种高精度、非接触式的位移测量系统&#xff0c;在平板小车的运动监测与控制中发挥着核心作用。 一、系统组成 该系统主要由以下关键部件组成&#xff1a; 地面电气柜&#xff1a;包含地址jie码器等重要组件&a…

【Linux课程学习】:对操作系统(Operator System)的理解

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;Linux课程学习 &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 操作系统&#xff08;Operator system&#xf…

使用Cursor和Claude AI打造你的第一个App

大家好&#xff0c;使用Cursor和Claude AI打造应用程序是一个结合智能代码辅助和人工智能对话的创新过程。Cursor是一个编程辅助工具&#xff0c;它通过智能代码补全、聊天式AI对话和代码生成等功能&#xff0c;帮助开发者提高编程效率。Claude AI则是一个强大的人工智能平台&a…

创建springboot+vue项目相关配置问题

安装并配置jdk23 在官网下载jdk Java Downloads | Oracle 中国 下载完成后双击即可安装。 安装完成后配置环境变量 此电脑->右键->属性->高级系统设置 然后一直点击确定即可。 键盘上win r java -version 可以验证是否配置成功 下载并配置maven 在官网下…

React 中使用 Axios 进行 HTTP 请求

下面是一个案例&#xff0c;展示如何在 React 中使用 Axios 进行 HTTP 请求&#xff0c;包括 GET 和 POST 请求的使用。 1. 安装 Axios 确保项目中已安装 Axios&#xff0c;可以通过以下命令安装&#xff1a; npm install axios2. 创建一个简单的 React 应用 项目结构&…

Wekan看板安装部署与使用介绍

Wekan看板安装部署与使用介绍 1. Wekan简介 ​ Wekan 是一个开源的看板式项目管理工具&#xff0c;它的配置相对简单&#xff0c;因为大多数功能都是开箱即用的。它允许用户以卡片的形式组织和跟踪任务&#xff0c;非常适合敏捷开发和日常任务管理。Wekan 的核心功能包括看板…