我爱学算法之—— 二分查找(下)

我爱学算法之—— 二分查找(下)

一、寻找峰值

题目解析

在这里插入图片描述
对于这道题,给定一个数组nums,在这数组中,可能存在多个峰值元素,我们只需找到一个峰值,然后返回峰值索引即可。

峰值元素:严格大于左右相邻的元素。

题目中给定:nums[0]nums[n]可以看做负无穷。

算法思路

对于这道题,首先暴力解法:遍历整个数组,依次判断一个元素它是不是峰值元素。

暴力解法的时间复杂度是O(n);并且暴力解法它并没有用到题目中给的:nums[0]nums[n]可以看做负无穷这一个条件。

当我们遍历i位置时,有且仅有两种情况:递增/递减(题目给定 nums[i] != nums[i+1])。

i位置呈现递增趋势时,也就是nums[i] > nums[i+1],题目又给出nums[0] = nums[n] = -∞区间[left , i]:也就是左边区间内,因为最左侧是负无穷,所以左侧区间要么一直递增,要么既有递增也有递减(开始位置肯定是先递增在递减)如果一直递增,那i位置就是一个峰顶;如果既有递增也有递减,那左侧区间内一定存在峰顶。也就是说,左侧区间内一定存在峰顶区间[i+1 , right]:也就是右侧区间,因为最右侧是负无穷,所以右侧区间可能一直递减,也可能既有递增也有递减如果一直递减,那右侧区间就不存在峰顶(因为nums[i+1] < nums[i]);如果既有递增也有递减,那右侧区间是存在峰顶的。那也就是说,右侧区间不一定存在峰顶

同理,如果i位置呈递减趋势,也就是nums[i] < nums[i+1]时:左侧区间不一定存在峰顶右侧区间一定存在峰顶

所以,遍历i位置时,就会把数组划分成区间[left , i]和区间[i+1 , right];这两个区间一个是一定存在峰顶的,一个是不一定存在峰顶的。

所以我们就可以根据二段性,使用二分查找算法

定义left,right,取mid = left + (right - left)/2如果nums[mid] > nums[mid+1]:左侧区间一定存在峰顶,去左侧区间查找如果nums[mid] < nums[mid+1]:右侧区间一定存在峰顶,去右侧区间查找
在这里插入图片描述

代码实现

classSolution{public:intfindPeakElement(vector<int>& nums){int l =0, r = nums.size()-1;while(l < r){int mid = l +(r - l)/2;if(nums[mid]> nums[mid +1]) r = mid;else l = mid +1;}return l;}};

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

题目解析

在这里插入图片描述
对于这道题,给定一个数组,这个数组是由一个有序的数组经过1-n次旋转得来的;

每一次旋转,就是将数组的最后一个元素放到数组的开头。

题目中还告诉我们数组nums中的元素互不相同。

最后让我们找到数组nums中的最小值,然后返回。

算法思路

暴力解法:

遍历整个数组,找到数组中的最小值,然后返回。

题目中告诉我们,nums数组是由一个有序的数组经过旋转得来的;而每一次旋转都是将数组的最后一个元素放到数组的第一个位置。

那这样我们的数组nums中的数据,前一部分是递增的,后一部分也是递增的;并且前一部分的数据都是大于后一部分的数据的。(因为旋转前数据是有序的

但是有一个特殊情况,数组nums也可以是有序的;也就是原数组旋转之后的数组nums和它自己是一样的。

所以数组nums就可以分为两部分,一部分是大于nums[n-1]的;另一部分是小于等于nums[n-1]的。

我们就可以利用该二段性,使用二叉查找算法

而我们要查找数组nums中的最小值,很显然我们要查找的最终结果在小于nums[n-1]的部分,且是该部分的最左端。

所以我们数组nums中的最小值就变成了,查找大于等于nums[n-1]区间的左端点。

定义left,right,取mid = left + (right - left)/2

如果nums[mid] > nums[n-1]:我们查找的最终结果位于区间[mid+1 , right]

如果nums[mid] <= nums[n-1]:我们查找的最终结果位于区间[left , mid]

特殊情况,如果数组nums是有序的,我们查找的是小于nums[n-1]的区间左端点,也是最终结果。

在这里插入图片描述

代码实现

classSolution{public:intfindMin(vector<int>& nums){int n = nums.size();int l =0, r = n -1;while(l < r){int mid = l +(r - l)/2;if(nums[mid]> nums[n -1]) l = mid +1;else r = mid;}return nums[l];}};

三、点名 - 力扣

题目解析

在这里插入图片描述
n名同学学号是0 ~ n-1,现在给定一个数组(点名结果记录)records,现在有一个同学缺席,现在我们要找到这个缺席的学生的学号。

例如:0,1,2,3,5,数组中不存在4

算法思路

对于这道题,还是比较简单的,解法有有很多种:

hash表,使用hash表来记录每一个数字,最后遍历hash表找到没有出现的数字。暴力查找,遍历整个数组,依次查找找到第一个数据和下标不相等的元素。按位与运算:x&x = 00&x = x;所以遍历整个元素,依次按位与上元素和下标+1,这样最后结果就是缺失的数字。数学运算,求出1-n的和,然后依次减去每一个元素,最终结果就是缺失的数字。

当然,上述的解法的时间复杂度都是O(n)的;

我们知道数组中的数据是0~n,是缺失一个数字的;那这个缺失的数字把数组分成了两部分:

左侧区域:数组中的数据和下标是相等的;右侧区域:数组中的数据和下标是不相等的。

而我们要查找的是右侧区域的左端点的下标,因为这个下标就是缺失的数字;

所以,我们就可以利用该二段性使用二分查找

定义left,right,取mid如果records[mid] == mid:我们要查找的最终结果在区间[mid+1 , right]中 -> left = mid+1;如果records[mid] != mid:我们要查找的最终结果在区间[left , mid]中 -> right = mid;

这里有个特殊情况,就是数组缺失的是最后一个元素,此时是不存在records[i] != i的区间的;

进行特殊处理,如果records[n-1] == n-1,就返回records[n-1] + 1

在这里插入图片描述

代码实现

classSolution{public:inttakeAttendance(vector<int>& records){if(records.back()== records.size()-1)return records.back()+1;int l =0, r = records.size()-1;while(l < r){int mid = l +(r - l)/2;if(records[mid]== mid) l = mid +1;else r = mid;}return l;}};

到这里本篇文章内容就结束了,感谢各位大佬的支持

Read more

超酷!前端人必备的 3 个 Skills:搞定高级 UI,拿捏最佳实践,最后一个直接拉满“续航”!

最近和几位前端开发者聊天,发现一个有趣的现象:AI 写代码越来越快,但代码质量的差距反而越来越大。 有人用 Cursor 写出来的页面,一眼就能看出是 AI 生成的——紫色渐变背景、Inter 字体、千篇一律的卡片布局。而有的人用同样的工具,却能产出让人眼前一亮的作品。 差距在哪里?不在 AI 工具本身,而在于你给 AI 注入了什么样的"技能包" 。 今天想分享前端开发必备的三个 Skills。前两个是干货分享,能立刻提升你的代码质量;第三个可能出乎你的意料,但确实是我最近的真实体会。 Skill 1: 让 AI 懂设计,告别"AI 味"的界面 你有没有遇到过这种情况——AI 生成的页面虽然能用,但总觉得哪里不对劲? 布局平庸、配色单调、

By Ne0inhk
进阶数据结构: AVL树

进阶数据结构: AVL树

嘿,各位技术潮人!好久不见甚是想念。生活就像一场奇妙冒险,而编程就是那把超酷的万能钥匙。此刻,阳光洒在键盘上,灵感在指尖跳跃,让我们抛开一切束缚,给平淡日子加点料,注入满满的passion。准备好和我一起冲进代码的奇幻宇宙了吗?Let's go! 我的博客:yuanManGan 我的专栏:C++入门小馆 C言雅韵集 数据结构漫游记  闲言碎语小记坊 题山采玉 领略算法真谛 目录 AVL相关概念:  AVL树的结构 Insert  旋转 右旋: 编辑 左单旋:  右左双旋: 左右双旋:  完整的插入: 其他简单的操作:  测试: AVL相关概念: AVL树是由二叉搜索树加上一定的限制而形成的树,AVL树:它的左右子树都是AVL树,且左右子树的高度差的绝对值不超过1。AVL树是⼀颗⾼度平衡搜索⼆叉树, 通过控制⾼度差去控制平衡。

By Ne0inhk
【DFS】天子呼来不上船,自称臣是酒中仙 - 2.递归

【DFS】天子呼来不上船,自称臣是酒中仙 - 2.递归

本篇博客给大家带来的是DFS深度优先遍历的解法技巧,在后面的文章中题目会涉及到回溯和剪枝,遇到了一并讲清楚. 🐎文章专栏: DFS 🚀若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅🚀 * 要开心 * 要快乐 * 顺便进步 * 1. 反转链表 * * 2. 两两交换链表中的节点 * * 要开心 要快乐 顺便进步 1. 反转链表 题目链接:206. 反转链表 题目内容: 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例 3: 输入:head = [] 输出:[] 提示: 链表中节点的数目范围是 [0, 5000] -5000 <= Node.val <

By Ne0inhk