LeetCode - 旋转数组类总结(二分法)

2023-11-12

搜索旋转排序数组

假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -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

分析: 二分搜索,之前二分搜索只是用到了有序数组中,在有旋转的数组中直接应用并不适用。 旋转数组存在两个有序的序列,我们只需判断每次要查找的范围在哪个有序序列中查找,就可以应用二分查找。如果中间的数大于等于最左边的数,则左半段是有序的,若中间数小于等于最左边数,则右半段是有序的,我们只要在有序的半段里用首尾两个数组来判断目标值是否在这一区域内,这样就可以确定保留哪半边了。

class Solution {
public:
	int search(vector<int>& nums, int target) {
		if (nums.size()== 0) {
			return -1;
		}
		int start = 0;
		int end = nums.size() - 1;
		int mid;
		while (start <= end) {
			mid = start + (end - start) / 2;
			if (nums[mid] == target) {
				return mid;
			}
            //防止出现重复数据
			if (nums[start] == nums[mid]) {
				start++;
				continue;
			}
			//前半部分有序start~mid有序,后续序列无序
			if (nums[start] <=nums[mid]) {
				//target在前半部分
				if (nums[mid] > target && nums[start] <= target) {
					end = mid - 1;
				}
				else {  //否则,去后半部分找
					start = mid + 1;
				}
			}
			else {
				//后半部分有序
				//target在后半部分
				if (nums[mid] < target && nums[end] >= target) {
					start = mid + 1;
				}
				else {  //否则,去前半部分找
					end = mid - 1;

				}
			}
		}
		//一直没找到,返回false
		return -1;
	}
};

搜索旋转排序数组 II

假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,0,1,2,2,5,6] 可能变为 [2,5,6,0,0,1,2] )。编写一个函数来判断给定的目标值是否存在于数组中。若存在返回 true,否则返回 false。这是 搜索旋转排序数组 的延伸题目,本题中的 nums 可能包含重复元素
示例 1: 输入: nums = [2,5,6,0,0,1,2], target = 0。 输出: true
示例 2: 输入: nums = [2,5,6,0,0,1,2], target = 3 。 输出: false

分析: 本题是需要使用二分查找,怎么分是关键,举个例子:

第一类: 10111 和 11101 这种。此种情况下 nums[start] ==nums[mid],分不清到底是前面有序还是后面有序,此时 start++ 即可。相当于去掉一个重复的干扰项。

第二类: 2 3 4 5 6 7 1 这种,也就是 nums[start] < nums[mid]。此例子中就是 2 < 5;这种情况下,前半部分有序。因此如果 nums[start] <=target<nums[mid],则在前半部分找,否则去后半部分找。

第三类: 6 7 1 2 3 4 5 这种,也就是 nums[start] > nums[mid]。此例子中就是 6 > 2;这种情况下,后半部分有序。因此如果 nums[mid] <target<=nums[end]。则在后半部分找,否则去前半部分找。

class Solution {
public:
	bool search(vector<int>& nums, int target) {
		if (nums.size()== 0) {
			return false;
		}
		int start = 0;
		int end = nums.size() - 1;
		int mid;
		while (start <= end) {
			mid = start + (end - start) / 2;
			if (nums[mid] == target) {
				return true;
			}
			if (nums[start] == nums[mid]) {
				start++;
				continue;
			}
			//前半部分有序
			if (nums[start] <=nums[mid]) {
				//target在前半部分
				if (nums[mid] > target && nums[start] <= target) {
					end = mid - 1;
				}
				else {  //否则,去后半部分找
					start = mid + 1;
				}
			}
			else {
				//后半部分有序
				//target在后半部分
				if (nums[mid] < target && nums[end] >= target) {
					start = mid + 1;
				}
				else {  //否则,去后半部分找
					end = mid - 1;

				}
			}
		}
		//一直没找到,返回false
		return false;
	}
};

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

假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。请找出其中最小的元素。你可以假设数组中不存在重复元素。(考虑重复)
示例 1: 输入: [3,4,5,1,2] 输出: 1
示例 2: 输入: [4,5,6,7,0,1,2] 输出: 0

分析: left一直指向左边有序序列的下标,right一直指向右边有序序列的下标。如果mid下标的值落在左边序列,则left=mid, 如果mid下标的值落在右边序列,则right=mid。当right-left==1为真时,最小值的下标为right。

class Solution {
public:
    int findMin(vector<int>& nums) {
        if (nums.size() == 0)
			return -1;
        if(nums.size()==1)
            return nums[0];
        //未旋转
        if(nums[0]<=nums[nums.size()-1])
           return nums[0];
		//先找到旋转数组的最小数字的下标
		int left = 0;
		int right = nums.size() - 1;
		int mid = 0;
		while (nums[left] >=nums[right]) {
			if (right - left == 1)
				break;
			mid = (left + right) / 2;
			if(nums[mid] == nums[left]&&nums[mid] == nums[right]) //10111 11101这种情况 其实是顺序查找最小值
				return findInOrder(left,right); //o(n)
			if (nums[mid] >= nums[left])
				left = mid;
			if (nums[mid] <= nums[right])
				right = mid;
		}
		return nums[right];
        
    }
};

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

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。你的算法时间复杂度必须是 O(log n) 级别。如果数组中不存在目标值,返回 [-1, -1]。

示例 1: 输入: nums = [5,7,7,8,8,10], target = 8 ,输出: [3,4]
示例 2: 输入: nums = [5,7,7,8,8,10], target = 6, 输出: [-1,-1]

分析: 先找到其中一个下标值为target的下标。再分别用二分查找找左下标和右下标。

class Solution {
public:
	vector<int> searchRange(vector<int>& nums, int target) {
		int left = 0;
		int right = nums.size() - 1;
		int mid = 0;
		int find = -1;
		vector<int> res;
		//先找到其中一个下标值为target的下标。
		while (left <= right) {
			mid = (left + right) / 2;
			if (target ==nums[mid])
			{
				find = mid;
				break;
			}
			else if (target > nums[mid])
				left = mid + 1;
			else
				right = mid - 1;
		}
		if (find == -1)
		{
			res = vector<int>{ -1,-1 };
			return res;
		}
		//找左边
		left = 0;
		right = find;
		while(left<=right){
			mid = (left + right) / 2;
			if (nums[mid] == target)
			{
				if (mid - 1 < 0 || nums[mid - 1] != target)
				{
					res.push_back(mid);
					break;
				}
				else
					right = mid - 1;
			}
			else
				left = mid + 1;
		}
		//找右边
		left = find;
		right = nums.size()-1;
		while (left <= right) {
			mid = (left + right) / 2;
			if (nums[mid] == target)
			{
				if (mid + 1 == nums.size() || nums[mid + 1] != target)
				{
					res.push_back(mid);
					break;
				}
				else
					left = mid + 1;
			}
			else 
				right = mid - 1;

		}
		return res;

	}
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LeetCode - 旋转数组类总结(二分法) 的相关文章

随机推荐

  • QT5开发之 信号与槽机制

    文章目录 什么是信号与槽 信号与槽原理 如何实现信号与槽机制 实现方式 UI方式 代码方式 QT4 QObject类 connect和disconnect 连接函数 QT4 QT5使用 找到类与类的信号与槽函数 QT4 QT5使用 举例 总
  • Windows下 Cppcheck 的使用教程

    1 Cppcheck是什么 CppCheck是一个C C 代码缺陷静态检查工具 不同于C C 编译器及其它分析工具 CppCheck只检查编译器检查不出来的bug 不检查语法错误 所谓静态代码检查就是使用一个工具检查我们写的代码是否安全和健
  • 计算机窗口移动不了怎么办,电脑鼠标拖不动文件怎么办 电脑鼠标拖动不灵敏如何解决...

    在我们使用电脑的时候 往往都会用到鼠标拖动文件 不知道有没有遇到过电脑鼠标拖不动文件的时候 这种情况大家是怎么解决的呢 不知道没关系 下面小编为大家带来电脑鼠标拖不动文件的解决方法 大家可以按照下面的步骤即可解决 电脑鼠标拖不动文件怎么办
  • 支付宝支付回调,回调日志记录

    1 支付报支付回调方法 public function aliPayNotify try app PayService alipay collect app gt verify collectData collect gt all 获取支付
  • 【Zabbix实战之运维篇】Zabbix监控平台的简单性能调优

    Zabbix实战之运维篇 Zabbix监控平台的简单性能调优 一 Zabbix性能优化介绍 1 造成Zabbix服务器变慢原因 2 Zabbix性能调优的方法 二 检查Zabbix服务器的资源占用情况 1 检查Zabbix各组件容器的资源占
  • [转载]YUV格式纹理贴图的例子

    frameworks native opengl tests gl2 yuvtex gl2 yuvtex cpp 是Android提供的yuv格式纹理贴图的例子 前面先申请存放纹理数据的buffer yuvTexBuffer new Gra
  • 根据哈夫曼树构建哈夫曼编码

    实验题 构造哈夫曼树生成哈夫曼编码 编写一个程序 构造一棵哈夫曼树 输出对应的哈夫曼编码和平均查找长度 并对下表 所示的数据进行验证 单词及出现的频度 单词 The of a to and in that he is at on for H
  • Github下载任意版本的VsCode

    下载历史版本VsCode zip 下载链接由三部分组成 固定部分 commit id VSCode win32 x64 版本号 zip 固定部分 https vscode cdn azure cn stable Commit id 打开 v
  • 嵌入式linux通过systemd自启动一个python代码

    一直想实现一段自启动的代码 今天尝试了下 成功了 做个记录 首先 我用的是imx6ull处理器 嵌入式linux内核版本为4 9 88 然后 上位机用的虚拟机ubuntu22 04 01 先在ubuntu上面试了试 能够自启动 然后再下载到
  • linux系统调用(持续更新....)

    随着自己接触越来越多的linux的系统函数发现自己在linux系统调用方面有很多不足 每次遇到系统调用函数都要百度一遍看一下用法 所以我打算写一篇博客来记录在开发过程遇到的系统调用函数 方便自己查阅 本文持续更新 1 popen 函数 2
  • Unity-协同程序

    知识点一 Unity是否支持多线程 1 首先要明确一点Unity是支持多线程的 只是新开线程无法访问Unity相关对象的内容 Unity中的多线程 要记住关闭 Unity中去使用 如果说 我们一开始在Start内创建一个多线程 那么我们无法
  • 【算法】最近点对问题(暴力破解法)

    简单的画了一张图 通过暴力方式 进行一次比较获取两个点之间的最短距离 点对最近问题 暴力破解法 include
  • Maven Dependency设置,详解!

    come from http www javaeye com topic 240424 用了Maven 所需的JAR包就不能再像往常一样 自己找到并下载下来 用IDE导进去就完事了 Maven用了一个项目依赖 Dependency 的概念
  • 赶紧来修炼内功~字符串函数详解大全(二)

    目录 1 strncpy 重点 模拟实现 2 strncat 重点 模拟实现 3 strncmp 重点 模拟实现 写在最后 1 strncpy 该函数包含三个参数 前两个参数与上一篇文章中讲解的strcpy函数一样 一个目的地 一个源 第三
  • 【算法】分治、动态规划和贪心算法

    这三种算法非常相似 但是又有一些区别 理解如下 分治 把一个问题划分为若干子问题 求出子问题的最优解 再把子问题的最优解进行merge 最终得到原问题的最优解 动态规划 原问题的最优解包含子问题的最优解 即 拥有最优子结构 同时 求子问题的
  • React Router 从v3升级到v4的踩坑之旅

    React 应用很少不用react router这个包的 marknoteapp com之前一直用v3 看到v4出来后一直心痒 最近 抱着 用新不用旧 的理念 手贱升了一下级 这一升级 差不多2天功夫花掉啦 概述 和 Angular 那改朝
  • 通过java api提交自定义hadoop 作业

    通过API操作之前要先了解几个基本知识 一 hadoop的基本数据类型和java的基本数据类型是不一样的 但是都存在对应的关系 如下图 如果需要定义自己的数据类型 则必须实现Writable hadoop的数据类型可以通过get方法获得对应
  • 未来科技计算机作文600字,未来的科技作文600字

    未来的科技是什么样的呢 也许大家都很好奇 未来可能有像人一样的机器人 未来的汽车能在天上飞 电脑也会有思维会说话谈感情 现在让我们一起去畅想未来的世界吧 清晨 我正懒洋洋地睡在床上 蒙眬中听见一阵音乐把我给弄醒了 小主人 起床的时间到了 家
  • Elasticsearch 入门到精通-ES可视化查询工具kibana重启

    ps ef grep kibana ps ef grep 5601 都找不到 尝试 使用 fuser n tcp 5601 kill 9 端口 ps ef grep node 或 netstat anltp grep 5601 启动即可 k
  • LeetCode - 旋转数组类总结(二分法)

    搜索旋转排序数组 假设按照升序排序的数组在预先未知的某个点上进行了旋转 例如 数组 0 1 2 4 5 6 7 可能变为 4 5 6 7 0 1 2 搜索一个给定的目标值 如果数组中存在这个目标值 则返回它的索引 否则返回 1 你可以假设数