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

L52.【LeetCode题解】二分法习题集1

目录

1.模版回顾

2.LCR 072. x 的平方根

分析

代码

提交结果

3.搜索插入位置

分析

代码

提交结果

4.LCR 069. 山脉数组的峰顶索引

题目

分析

二分法代码

使用左边界模版

提交结果

使用右边界模版

提交结果

也可以分三部分

代码

提交结果


1.模版回顾

参见以下文章:

CC53.【C++ Cont】二分查找的普通模版

CC54.【C++ Cont】二分查找的左、右边界模版

2.LCR 072. x 的平方根

https://leetcode.cn/problems/jJ0w9p/description/

给定一个非负整数 x ,计算并返回 x 的平方根,即实现 int sqrt(int x) 函数。

正数的平方根有两个,只输出其中的正数平方根。

如果平方根不是整数,输出只保留整数的部分,小数部分将被舍去。

示例 1:

输入: x = 4
输出: 2

示例 2:

输入: x = 8
输出: 2
解释: 8 的平方根是 2.82842...,由于小数部分将被舍去,所以返回 2

提示:

  • 0 <= x <= 231 - 1

注意:本题与主站 69 题相同: 69. x 的平方根 - 力扣(LeetCode)

分析

补L51.【LeetCode题解】LCR 072. x 的平方根 (6种方法)文章未讲的方法6:二分法

从暴力解法优化:

L51文章暴力解法:

由于题目说了"如果平方根不是整数,输出只保留整数的部分,小数部分将被舍去",那就可以一个一个枚举所有整数

class Solution {
public:int mySqrt(int x) {for (long long i=0;i<=x;i++){if (i*i<=x&&(i+1)*(i+1)>x)return i;}return -1;}
};

暴力解法的意思枚举1^22^23^2、......、n^2,直到某个数c的c^2不超过x的最大整数

如果从1开始枚举将会很慢,可以采用二分法

注意到不超过x的最大整数是小于等于x,符合右边界的要求

直接使用模版:

//能进入循环的前提是数组不为空!!!
while (left < right)
{int mid = left + (right - left + 1) / 2;if (......)left = mid;elseright = mid - 1;
}

改一下if判断的处理即可

代码

class Solution {
public:int mySqrt(int x) {if (x==0)return 0;int left=1,right=x;while (left < right){unsigned long long mid = left + (right - left + 1) / 2;if (mid*mid<=x)left = mid;elseright = mid - 1;}return left;}
};

注意if判断中是mid*mid,如果mid为int类型很有可能会溢出,因此将mid的数据类型的范围适当定大些

提交结果

3.搜索插入位置

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

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

请必须使用时间复杂度为 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 <= 10^4
  • -10^4 <= nums[i] <= 10^4
  • nums 为 无重复元素 的 升序 排列数组
  • -10^4 <= target <= 10^4

分析

题目已经提示时间复杂度为O(NlogN),读题"nums 为 无重复元素 的 升序 排列数组",可以利用数组的有序性来使用二分法

对于没有找到target的情况要在循环结束后单独判断,插入位置的特点:大于target的第一个数的下标

直接使用二段性划分:

 显然是寻找左边界,使用CC54.【C++ Cont】二分查找的左、右边界模版文章的左边界模版:

//能进入循环的前提是数组不为空!!!
while (left < right)
{int mid = left + (right - left) / 2;if (......)left = mid + 1;elseright = mid;
}

注意这里不能直接使用模版,循环结束后还需要判断

因为如果nums[mid]==target,直接返回mid,因此

代码

while循环体的判断分2种情况:

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

或者while循环体的判断需要分3种情况:

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

left==right有两种情况

1.while循环修改left和right

2.没有进入while循环,数组中只有一个元素

因此在while循环结束后要写成if (nums[left]>=target),必须是>=,其中>=的=是考虑数组中只有一个元素的情况

提交结果

4.LCR 069. 山脉数组的峰顶索引

题目

符合下列属性的数组 arr 称为 山峰数组山脉数组)

  • arr.length >= 3
  • 存在 i0 < i < arr.length - 1)使得:
    • arr[0] < arr[1] < ... arr[i-1] < arr[i]
    • arr[i] > arr[i+1] > ... > arr[arr.length - 1]

给定由整数组成的山峰数组 arr ,返回任何满足 arr[0] < arr[1] < ... arr[i - 1] < arr[i] > arr[i + 1] > ... > arr[arr.length - 1] 的下标 i ,即山峰顶部。

示例 1:

输入:arr = [0,1,0]
输出:1

示例 2:

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

示例 3:

输入:arr = [0,10,5,2]
输出:1

示例 4:

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

示例 5:

输入:arr = [24,69,100,99,79,78,67,36,26,19]
输出:2

提示:

  • 3 <= arr.length <= 10^4
  • 0 <= arr[i] <= 10^6
  • 题目数据保证 arr 是一个山脉数组

进阶:很容易想到时间复杂度 O(n) 的解决方案,你可以设计一个 O(log(n)) 的解决方案吗?

分析

要求"设计一个 O(log(n)) 的解决方案",显然使用二分法,二分法的使用前提:符合二段性,显然山脉数组是符合的

(二段性的介绍在CC53.【C++ Cont】二分查找的普通模版文章)

例如以下山脉数组:

显然可以分两部分:

红框元素严格单调递增,arr[mid]>arr[mid-1]

蓝框元素严格单调递减,arr[mid]>arr[mid+1]

需要寻找红框的边界元素,即左边界,使用左边界模版:

//能进入循环的前提是数组不为空!!!
while (left < right)
{int mid = left + (right - left) / 2;if (......)left = mid + 1;elseright = mid;
}

或者这样分:

红框元素严格单调递增,arr[mid]>arr[mid-1]

蓝框元素严格单调递减,arr[mid]>arr[mid+1]

需要寻找蓝框的边界元素,使用右边界模版: 

//能进入循环的前提是数组不为空!!!
while (left < right)
{int mid = left + (right - left + 1) / 2;if (......)left = mid;elseright = mid - 1;
}

二分法代码

使用左边界模版

class Solution {
public:int peakIndexInMountainArray(vector<int>& arr) {int left=0;int right=arr.size()-1;while (left < right){int mid=left+(right-left)/2;if (arr[mid]>arr[mid-1])left=mid;if (arr[mid]>arr[mid+1])right=mid;}return left;}
};
提交结果

使用右边界模版

class Solution {
public:int peakIndexInMountainArray(vector<int>& arr) {int left=0;int right=arr.size()-1;while (left < right){int mid=left+(right-left+1)/2;if (arr[mid]>arr[mid-1])left=mid;elseright=mid-1;}return left;}
};
提交结果

也可以分三部分

代码

class Solution {
public:int peakIndexInMountainArray(vector<int>& arr) {int left=0;int right=arr.size()-1;while(left<right){int mid=left+(right-left)/2;if (arr[mid]>arr[mid+1]&&arr[mid]>arr[mid-1])return mid;if (arr[mid]<arr[mid+1]&&arr[mid]>arr[mid-1])left=mid;if (arr[mid]>arr[mid+1]&&arr[mid]<arr[mid-1])right=mid;}return 0;//能找到峰值,这里随意返回一个数}
};
提交结果

http://www.xdnf.cn/news/6799.html

相关文章:

  • BigemapPro小技巧:如何只显示特定区域内的点
  • Linux 内核版本详解
  • 数据中心末端配电监控产品
  • STM32F407VET6实战:CRC校验
  • Python-homework
  • 1Panel应用推荐:Beszel轻量级服务器监控平台
  • UE RPG游戏开发练手 第二十七课 普通攻击2
  • 使用Mathematica制作Lorenz吸引子的轨道追踪视频
  • 海盗王3.0的数据库3合1并库处理方案
  • 【全解析】EN18031标准下的SUM安全更新机制
  • VBA技术资料MF306:删除与正则表达式匹配的文件
  • 10 大医学数据集汇总:覆盖问答/推理/真实临床记录/超声图像/CT 影像……
  • 多网卡管理实战指南:原理、问题分析与实用工具推荐
  • vs2019及以后版本cmd指定编译环境文件的路径
  • Linux》Ubuntu》安装Harbor 私有仓库
  • Manim教程:第12章 函数,函数图像和文字的渲染
  • 高清箱号识别系统:模糊集装箱号的高效识别解决方案
  • ”一维前缀和“算法原理及模板
  • 多线程八股文(自用)
  • SOLIDWORKS Simulation接触定义精讲(一)
  • CVE-2017-8046 漏洞深度分析
  • 【每天一个知识点】意图传播(Intent Propagation)
  • AG 视频下载 免费分享
  • 从零开始学习three.js(19):一文详解three.js中的辅助类Helper
  • 彻底删除Docker容器中的环境变量
  • 【Kuberbetes】详谈网络(第三篇)
  • 机器学习中的特征工程:解锁模型性能的关键
  • Mysql数据库详解
  • 最小二乘法:从房价预测到损失计算
  • 从裸机开发到实时操作系统:FreeRTOS详解与实战指南