【算法】二分相关题目

news2024/11/25 20:24:45

文章目录

  • 二分相关
    • 二分查找
    • 在排序数组中查找元素的第一个和最后一个位置
    • 寻找峰值
    • x 的平方根
    • 0~n-1中缺失的数字
    • ## 搜索插入位置

二分相关

二分查找

https://leetcode.cn/problems/binary-search/

在一个有序数组当中,查找值为target的元素,返回下标

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0,right = nums.size()-1;
        //当二者指向同一个元素的时候也要判断
        //例如:nums:[5] target:5 如果写成left < right 那么返回-1是错误的!应该返回的是0
        while(left <= right) 
        {
            int mid = (left + right) / 2;
            if(nums[mid] > target)
                right = mid - 1; //去左侧找
            else if(nums[mid] < target)
                left = mid + 1; //去右侧找
            else 
                return mid;
        }   
        return -1;
    }
};

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

https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/

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

  • 本质是:在有序数组当中,找>=某个数最左侧的位置,找<=某个数最右侧的位置
  • 但是这里要求必须要找到严格等的位置

image-20230911214124788

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int n = nums.size();
        vector<int> ans;
        if(n == 0) return {-1,-1};
        //1.找>=tarhet元素的最左边位置
        int left = 0,right = n-1;
        int index = 0;//记录位置
        while(left <= right)
        {
            int mid = (left + right) / 2;
            if(nums[mid] >= target)
            {
                index = mid;
                right = mid -1; //去左侧找更接近的
            }
            else 
                left = mid + 1;
        }
        //判断数组是否存在值为target的元素
        if(nums[index] != target) return {-1,-1};
        
        ans.push_back(index);

        //2.找<=target元素的最右边位置
        left = 0,right = n - 1;
        while(left <= right)
        {
            int mid = (left + right) / 2;
            if(nums[mid] <= target)
            {
                index = mid;
                left = mid +1;//去右侧找更接近的答案
            }
            else 
                right = mid - 1;
        }
        ans.push_back(index);
        return ans;
    }
};

寻找峰值

https://www.nowcoder.com/practice/fcf87540c4f347bcb4cf720b5b350c76?tpId=295&tqId=2227748&ru=/exam/company&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Fcompany

给定一个长度为n的数组nums,请你找到峰值并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个所在位置即可。

1.峰值元素是指其值严格大于左右相邻值的元素。严格大于即不能有等于

2.假设 nums[-1] = nums[n] = − ∞ −∞

3.对于所有有效的 i 都有 nums[i] != nums[i + 1]

image-20230911215013466


方法1:直接遍历数组,如果当前元素比周围两个元素都大,说明当前元素就是峰值元素

int findPeakElement(vector<int>& nums) 
{
    //特判第一个元素和最后一个元素
    int n = nums.size();
    if(nums[0] > nums[1]) return 0;
    if(nums[n-1] > nums[n-2]) return n - 1;
    //判断[1,n-2]位置的元素,看哪个位置的元素满足比周围元素都大
    for(int i = 1;i<=n-2;i++)
    {
        if(nums[i] > nums[i-1] && nums[i] > nums[i+1])
            return i;
    }
    return -1;
}

方法2:二分查找

只要出现 /\这种形式,就是峰值,如果中间位置不是峰值,那么肯定有一边的值比中间位置的值大

int findPeakElement(vector<int>& nums) {
    //特判第一个元素和最后一个元素
    int n = nums.size();
    if (nums[0] > nums[1]) return 0;
    if (nums[n - 1] > nums[n - 2]) return n - 1;
    //在[1,n-2]范围上进行二分
    int left = 1,right = n-2;
    while(left <= right)
    {
        int mid = (left + right)  /2;
        if(nums[mid] < nums[mid+1]) //从mid到mid+1呈现上升趋势(/)
        {
            left = mid + 1;//去右边找下降(\)趋势,就能找到峰值
        }
        else if(nums[mid] < nums[mid-1]) //mid-1到mid呈现下降趋势(\)
        {
            right = mid - 1;//去左边找上升(/)趋势,就能找到峰值
        }
        else  //nums[mid] > nums[mid+1] && nums[mid] > nums[mid-1]
            return mid;
    }
    return -1;
}

x 的平方根

https://leetcode.cn/problems/sqrtx/

image-20220610213413702

方法1:暴力求解:枚举 [ 0 , x ] [0,x] [0,x]的所有数进行判断

class Solution {
    public:
    int mySqrt(int x) {
        // 由于两个较⼤的数相乘可能会超过 int 最⼤范围  因此⽤ long long
        long long i = 0;
        for (i = 0; i <= x; i++)
        {
            // 如果两个数相乘正好等于 x,直接返回 i
            if (i * i == x) return i;
            // 如果第⼀次出现两个数相乘⼤于 x,说明结果是前⼀个数
            if (i * i > x) return i - 1;
        }
        // 为了处理oj题需要控制所有路径都有返回值
        return -1;
    }
};

方法2:使用二分。用long是为了防止mid*mid过大导致溢出!当然也可以将判断条件写成下面这种: i f ( m i d ∗ m i d > x ) 等价于 = > i f ( m i d > ( x / m i d ) ) if(mid*mid>x) 等价于=> if(mid>(x/mid)) if(midmid>x)等价于=>if(mid>(x/mid))

image-20230907221513216

class Solution {
public:
    int mySqrt(int x) {
        //二分法
        if(x == 0)    return 0;
        if(x<=3) return 1;
        //在[1,x]范围进行二分
        long left = 1;
        long right = x;
        long ans = 1;//记录答案
        while(left <= right)//当left和right指向同一个数也需要判断
        {
            long mid = left +(right - left)/2;
            if(mid*mid > x)
            {
                //去左边二分
                right = mid-1;
            }
            else
            {
                //记录答案,继续去右边查找
                left = mid+1;
                ans = mid;
            }
        }
        return (int)ans;
    }
};

0~n-1中缺失的数字

https://leetcode.cn/problems/que-shi-de-shu-zi-lcof/description/

一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字

输入: [0,1,3]		输出: 2		输入: [0,1,2,3,4,5,6,7,9]		输出: 8

因为数组是有序的,方法1:使用哈希表 方法2:直接遍历 方法3:使用位运算 方法 4:高斯求和公式

class Solution {
public:
    //方法1:使用哈希表
    int missingNumber(vector<int>& nums) {
      unordered_map<int,int> um;
      int n = nums.size();
      for(auto& x:nums)  //在哈希表当中做映射
        um[x]++;
      for(int i = 0;i<=n;i++)
      {
        if(um[i] == 0)  //该元素不在哈希表当中存在=>说明是缺失的数字
          return i;
      }
      return -1;
    }
};
//方法2:直接遍历
class Solution {
public:
    int missingNumber(vector<int>& nums) {
      int n = nums.size();
      for(int i = 0;i<n;i++)
      {
        //数组是有序的
        if(nums[i] != i) return i;  
      }
      return n;//说明缺失的元素是n
    }
};
//方法3:位运算
class Solution {
public:
    int missingNumber(vector<int>& nums) {
      int n = nums.size();
      int miss = 0;
      for(auto& x:nums) miss ^= x; //先和原数组的所有元素进行以异或
      for(int i = 0;i<=n;i++) miss ^= i; //和[0,n]范围上的数进行异或
      return miss;
    }
};

//方法4:高斯求和公式
class Solution {
public:
    int missingNumber(vector<int>& nums) {
      //高斯求和公式:和= (首项+末项)x项数÷2
      int n = nums.size();
      int total = (0+n) * (n+1) / 2; 
      int sum = 0;
      for(auto& x:nums) sum+=x;
      return total - sum;//缺失的数
    }
};

方法5:二分算法

因为数组是升序排列的:

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

可以利⽤这个「⼆段性」,来使⽤「⼆分查找」算法

image-20230920152700473

  • 如果当前 n u m s [ m i d ] = = m i d nums[mid] == mid nums[mid]==mid :说明当前是在左边,要去右边找答案 l e f t = m i d + 1 left = mid + 1 left=mid+1
  • 如果当前 n u m s [ m i d ] ! = m i d nums[mid] != mid nums[mid]!=mid :说明当前在右边,要去左边找答案 r i g h t = m i d right = mid right=mid

最后:当跳出循环的时候,还要判断此时指向的值和数组当中的值是否相同,如果相同,那么说明缺失的是下一个数

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;
      }
      return left == nums[left] ? left + 1 : left;
    }
};

## 搜索插入位置

https://leetcode.cn/problems/search-insert-position/description/

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

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

插入位置的特点:第一次出现比它大的数的前一个位置 || 数组的最后一个位置 =>转化为找到 > = >= >=target的左端点即可

  • 直到我们的查找区间的⻓度变为1,也就是当$left == right 的时候,此时 的时候, 此时 的时候,此时left 或者 right$所在的位置就是我们要找的结果

细节:当跳出循环的时候,要判断当前 l e f t ( r i g h t ) left(right) left(right)位置的数和 t a r g e t target target的关系,来判断到底是插入到 l e f t ( r i g h t ) left(right) left(right)位置,还是最后一个位置

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
      int left = 0,right = nums.size()-1;
      int ans = 0;
      //找到>=target的最左边位置
      while(left < right)
      {
        int mid = (left + right) / 2;
        if(nums[mid] >= target)
          right = mid;
        else 
          left = mid + 1;
      }
      //如果nums[left] < target 说明应该插入到最后一个位置的后面
      if(nums[left] < target) return left+1;
      else return left;
    }
};

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

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

相关文章

SSM - Springboot - MyBatis-Plus 全栈体系(十七)

第三章 MyBatis 五、MyBatis 高级扩展 1. mapper 批量映射优化 1.1 需求 Mapper 配置文件很多时&#xff0c;在全局配置文件中一个一个注册太麻烦&#xff0c;希望有一个办法能够一劳永逸。 1.2 配置方式 Mybatis 允许在指定 Mapper 映射文件时&#xff0c;只指定其所在的…

2023年中国家用智能门锁市场发展概况分析:家用智能门锁线上市场销量290.4万套[图]

智能门锁是指区别于传统机械锁的基础上改进的&#xff0c;在用户安全性、识别、管理性方面更加智能化简便化的锁具。智能门锁是门禁系统中锁门的执行部件。智能门锁区别于传统机械锁, 是具有安全性, 便利性, 先进技术的复合型锁具。 智能门锁级别分类 资料来源&#xff1a;共研…

MARS: An Instance-aware, Modular and Realistic Simulator for Autonomous Driving

● MARS: An Instance-aware, Modular and Realistic Simulator for Autonomous Driving&#xff08;基于神经辐射场的自动驾驶仿真器&#xff09; ● https://github.com/OPEN-AIR-SUN/mars ● https://arxiv.org/pdf/2307.15058.pdf ● https://mp.weixin.qq.com/s/6Ion_DZGJ…

flink处理函数--副输出功能

背景 在flink中&#xff0c;如果你想要访问记录的处理时间或者事件时间&#xff0c;注册定时器&#xff0c;或者是将记录输出到多个输出流中&#xff0c;你都需要处理函数的帮助&#xff0c;本文就来通过一个例子来讲解下副输出 副输出 本文还是基于streaming-with-flink这本…

解决SpringBoot Configuration Annotation Processor not configured

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 问题描述 在使用ConfigurationProperties注解和EnableConfigurationProperties注解时&#xff0c;IDEA报错&#xff1a;SpringBoot Configuration Annotation Processor no…

【chainlit】使用chainlit部署chatgpt

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

微服务架构改造案例

最后一个部分&#xff0c;结合我们自己的财务共享平台项目进行了微服务架构改造案例分析。 对于改造前的应用&#xff0c;实际上存在四个方面的问题。 其一是关于高可用性方面的&#xff0c;即传统的单体应用我们在进行数据库水平扩展的时候已经很难扩展&#xff0c;已经出现…

XShell远程连接Ubuntu

环境 系统&#xff1a;Ubuntu 18.04.6 LTS IP&#xff1a;192.168.1.4 ps:查看ubuntu版本 lsb_release -a 查看ubuntu的ip地址 Ubuntu系统准备工作 root权限 打开ubuntu系统后&#xff0c;打开终端&#xff0c;切换为root权限&#xff1a;su root 如果出现su root认证失…

管理经济学基本概念(五):一些基本术语

1、理性-行动者范式 使经济学家行动一致的东西就是采用理性-行动者范式来预判人的行为。简单地说&#xff0c;这个范式认为人们的行动式理性的、优化的和自利的。 2、税后净营业利润 税后经营净利润(NOPAT)是指将公司不包括利息收支的营业利润扣除实付所得税税金之后的数额加…

Acwing 907. 区间覆盖

Acwing 907. 区间覆盖 知识点题目描述思路讲解代码展示 知识点 贪心 题目描述 思路讲解 代码展示 #include <iostream> #include <algorithm>using namespace std;const int N 100010;int n;struct Range {int l, r;bool operator < (const Range &W) …

【day11.02】网络编程脑图

大小端存储&#xff1a; ip地址划分&#xff1a;

MySQL 锁分类和详细介绍

锁是计算机协调多个进程或线程并发访问某一资源的机制&#xff0c;在数据库中&#xff0c;除传统的计算资源&#xff08;CPU、RAM、I/O&#xff09;的争用以外&#xff0c;数据也是一种供许多用户共享的资源&#xff0c;锁机制是保证数据一致性和并发性的重要手段&#xff0c;它…

软件设计模式系列之二十二——状态模式

1 模式的定义 状态模式是一种行为型设计模式&#xff0c;它允许对象在内部状态发生改变时改变其行为&#xff0c;使得对象的行为看起来像是改变了其类。状态模式将对象的状态抽象成一个独立的类&#xff0c;让对象在不同状态下具有不同的行为&#xff0c;而且可以在运行时切换…

做一个优秀的博士生,时间的付出是必要条件

&#xff0a;图片来自管理学季刊 时间的付出 所有成功的科学家一定具有的共同点&#xff0c;就是他们必须付出大量的时间和心血。这是一条真理。实际上&#xff0c;无论社会上哪一种职业&#xff0c;要想成为本行业中的佼佼者&#xff0c;都必须付出比常人多的时间。有时&…

【知识点随笔分析 | 第六篇】HTTP/1.1,HTTP/2和HTTP/3的区别

前言&#xff1a; 当今互联网已成为人们生活的重要组成部分&#xff0c;而HTTP协议&#xff08;Hypertext Transfer Protocol&#xff09;是支持Web通信的基础。随着Web技术的发展和互联网应用的不断增多&#xff0c;HTTP也在不断演进。本文旨在介绍HTTP的演变过程中的三个重要…

【Godot4.1】Godot实现闪烁效果(Godot使用定时器实现定时触发的效果)

文章目录 准备工作创建Sprite2D创建Timer节点 编写脚本完整代码运行效果 准备工作 如果你希望配置C#编写脚本&#xff0c;可以查看如下教程&#xff1a; Godot配置C#语言编写脚本 创建Sprite2D 首先弄一个用于显示的Sprite2D&#xff0c;右键单击任意节点&#xff0c;然后选…

Transformer在小目标检测上的应用

本篇文章是博主在AI、无人机、强化学习等领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对人工智能等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅解。文章分类在AI学…

mysql双主互从通过KeepAlived虚拟IP实现高可用

mysql双主互从通过KeepAlived虚拟IP实现高可用 在mysql 双主互从的基础上&#xff0c; 架构图&#xff1a; Keepalived有两个主要的功能&#xff1a; 提供虚拟IP&#xff0c;实现双机热备通过LVS&#xff0c;实现负载均衡 安装 # 安装 yum -y install keepalived # 卸载 …

反向输出一个三位数

系列文章目录 进阶的卡莎C++_睡觉觉觉得的博客-CSDN博客数1的个数_睡觉觉觉得的博客-CSDN博客双精度浮点数的输入输出_睡觉觉觉得的博客-CSDN博客足球联赛积分_睡觉觉觉得的博客-CSDN博客大减价(一级)_睡觉觉觉得的博客-CSDN博客小写字母的判断_睡觉觉觉得的博客-CSDN博客纸币(…

手把手教你完成(Java)师生信息管理系统

手把手教你完成&#xff08;Java&#xff09;师生信息管理系统 对阶段一学到的知识进行应用&#xff0c;完成练手小项目。同时&#xff0c;也可以当做学校的课设来做。项目已上传 CSDN &#xff0c;可以按需下载。 一、成果展示 添加学生&#xff08;查看学生&#xff09; 删除…