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

力扣hot100-lc34在排序数组中查找元素的第一个和最后一个位置/lc153寻找旋转排序数组中的最小值/lc33搜索旋转排序数组

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

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

给你一个按照非递减顺序排列的整数数组 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

🧠 题目思路总结:

本题要求在有序数组中找出目标值的起始和终止位置,且必须在 O(log n) 时间复杂度内完成,因此可以使用二分查找来实现。

我们使用一个辅助函数 lowerBound(nums, target) 实现 找第一个大于等于 target 的位置

  • 起始位置是 lowerBound(target)
  • 终止位置是 lowerBound(target + 1) - 1(即小于 target+1 的最后一个位置);
  • 如果 start == nums.length || nums[start] != target,说明 target 不存在。

✅ 一句话总结解法:

用两次二分查找分别定位 target 的第一个出现位置和最后一个位置。


💻 【Java 代码】

class Solution {public int[] searchRange(int[] nums, int target) {// 查找目标值的起始位置int start = lowerBound(nums, target);// 如果起始位置超出数组范围 或 nums[start] 不是目标值,说明不存在if (start == nums.length || nums[start] != target) {return new int[]{-1, -1};}// 查找目标值的结束位置:等于 lowerBound(target+1) 再往前一步int end = lowerBound(nums, target + 1) - 1;return new int[]{start, end};}// lowerBound:查找第一个大于等于 target 的索引private int lowerBound(int[] nums, int target) {int left = 0;int right = nums.length - 1;// 标准二分写法while (left <= right) {int mid = left + (right - left) / 2;// 如果中间值小于目标,说明目标在右边if (nums[mid] < target) {left = mid + 1;} else {// 否则向左收缩right = mid - 1;}}// 最终返回的是第一个 >= target 的位置return left;}
}

📌 示例运行演示:

  • 输入:nums = [5,7,7,8,8,10], target = 8
    • start = lowerBound(8) = 3
    • end = lowerBound(9) - 1 = 5 - 1 = 4
    • 返回 [3, 4]
  • 输入:nums = [5,7,7,8,8,10], target = 6
    • start = lowerBound(6) = 1
    • nums[1] = 7 != 6 → 返回 [-1, -1]

162. 寻找峰值(false)

刷题:https://leetcode.cn/problems/find-peak-element/

峰值元素是指其值严格大于左右相邻值的元素。

给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。

你可以假设 nums[-1] = nums[n] = -∞

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

示例 1:

输入:nums = [1,2,3,1]
输出:2
解释:3 是峰值元素,你的函数应该返回其索引 2。

示例 2:

输入:nums = [1,2,1,3,5,6,4]
输出:1 或 5 
解释:你的函数可以返回索引 1,其峰值元素为 2;或者返回索引 5, 其峰值元素为 6。

🔍【题目讲解】

峰值元素定义为:该元素大于它左右相邻的元素

基于二分查找的 局部单调性分析

  1. 比较中点与右侧元素
    • nums[mid] < nums[mid+1],说明右侧有更大的值,峰值在右侧,收缩左边界到 mid+1
    • 否则(nums[mid] > nums[mid+1]),说明峰值在左侧或 mid 处,收缩右边界到 mid
  2. 调整循环条件
    while(left <= right) 改为 while(left < right),确保循环结束时 left == right,避免越界且正确收敛到峰值索引。

💡【核心思路】——一句话总结:

利用二分查找判断中间值与右侧元素的大小关系,不断缩小搜索区间,最终锁定峰值索引。


📌【示例说明】

  • 示例1:[1,2,3,1]
    mid = 1 → nums[1]=2 < nums[2]=3 → 搜索右半边,最后找到索引2的元素3是峰值。
  • 示例2:[1,2,1,3,5,6,4]
    多个峰值,比如索引1处的2、索引5处的6,算法返回任意一个都正确。

✅【Java代码实现】:

public class Solution {public int findPeakElement(int[] nums) {int left = 0, right = nums.length - 1;while (left < right) {int mid = left + (right - left) / 2;// 如果中间值比右边大,峰值在左边(包含mid)if (nums[mid] > nums[mid + 1]) {right = mid;} else { // 否则峰值在右边left = mid + 1;}}return left; // 最终left == right,指向一个峰值元素}
}

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

https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/

已知一个长度为 n 的数组,预先按照升序排列,经由 1n旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:

  • 若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
  • 若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]

注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]]

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素

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

示例 1:

输入:nums = [3,4,5,1,2]
输出:1
解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。

示例 2:

输入:nums = [4,5,6,7,0,1,2]
输出:0
解释:原数组为 [0,1,2,4,5,6,7] ,旋转 4 次得到输入数组。

示例 3:

输入:nums = [11,13,15,17]
输出:11
解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。

提示:

  • n == nums.length
  • 1 <= n <= 5000
  • -5000 <= nums[i] <= 5000
  • nums 中的所有整数 互不相同
  • nums 原来是一个升序排序的数组,并进行了 1n 次旋转

🔍【题目讲解】

一个原本递增的数组经过多次旋转,形成了一个新的数组。由于数组元素互不相同,我们可以借助二分查找快速找出最小元素的位置


💡【核心思路】——一句话总结:

通过比较中间值与右端值的大小判断最小值所在区间,使用二分查找逐步缩小范围。


✅【Java代码实现】:

public class Solution {public int findMin(int[] nums) {int left = 0, right = nums.length - 1;while (left < right) {int mid = left + (right - left) / 2;// 如果中间值比右边大,最小值一定在右半区if (nums[mid] > nums[right]) {left = mid + 1;} else { // 否则最小值在左半区(包括mid)right = mid;}}// 循环结束时,left == right,指向最小值return nums[left];}
}

📌【示例说明】

  1. 输入:[3,4,5,1,2]
    • mid=2 nums[mid]=5 > nums[right]=2,所以最小值在右边;
    • 缩小范围后最终定位到索引3的1
  2. 输入:[4,5,6,7,0,1,2]
    • 二分查找不断右移,最终找到最小值为0
  3. 输入:[11,13,15,17]
    • 没有旋转,最小值就在左端,返回11

33. 搜索旋转排序数组

https://leetcode.cn/problems/search-in-rotated-sorted-array/

整数数组 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

🔍【题目讲解】

【有序区间判断】:

  • 左半有序的条件:nums[left] <= nums[mid]。例如,数组 [4,5,6,7,0,1,2] 中,当 mid=3 时,左半区间 [4,5,6,7] 有序。

  • 右半有序的条件:若左半无序,则右半一定有序。例如,当 mid=4 时,右半区间 [0,1,2] 有序。

【目标值范围决策】:

  • 左半有序时:若 target 在 [nums[left], nums[mid]) 范围内,则继续搜索左半;否则转向右半。

  • 右半有序时:若 target 在 (nums[mid], nums[right]] 范围内,则继续搜索右半;否则转向左半。

💡【核心思路】——一句话总结:

在二分过程中判断哪一边是有序的,再判断 target 是否在该有序区间内,从而决定向哪边搜索。


✅【Java代码实现】:

class Solution {public int search(int[] nums, int target) {int left = 0, right = nums.length - 1;while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] == target) {return mid; // 直接命中目标值[4,8](@ref)}// 判断左半部分是否有序if (nums[left] <= nums[mid]) { if (nums[left] <= target && target < nums[mid]) {right = mid - 1; // 目标在左半有序区间[4,8](@ref)} else {left = mid + 1;  // 目标在右半无序区间}} else { // 右半部分有序if (nums[mid] < target && target <= nums[right]) {left = mid + 1;  // 目标在右半有序区间[4,8](@ref)} else {right = mid - 1; // 目标在左半无序区间}}}return -1; // 未找到目标值}
}

📌【示例说明】

  1. 输入: nums = [4,5,6,7,0,1,2], target = 0
    • mid = 3, nums[3]=7,左边有序 [4,5,6,7],但 0 不在其中 → 继续搜索右半边 → 找到索引 4。
  2. 输入: nums = [4,5,6,7,0,1,2], target = 3
    • 无论怎么查找都不满足条件,最终返回 -1。
  3. 输入: nums = [1], target = 0
    • 只有一个元素且不等于目标值 → 返回 -1。

相关文章:

  • 3D打印入门
  • 使用 PyTorch 和 SwanLab 实时可视化模型训练
  • 京津冀城市群13城市空间权重0-1矩阵
  • 亚矩阵云手机针对AdMob广告平台怎么进行多账号的广告风控
  • imgui绘制图像(c++)
  • 《单光子成像》第二章 预习2025.6.12
  • 如何在SOLIDWORKS工程图中添加材料明细表?
  • linux共享内存解析
  • ArkUI-X构建Android平台AAR及使用
  • 复现论文报错解决
  • 基于mapreduce的气候分析系统
  • QCoreApplication QApplication
  • vue2项目开发中遇到的小问题
  • vue3集成高德地图绘制轨迹地图
  • 分割任意组织:用于医学图像分割的单样本参考引导免训练自动点提示方法|文献速递-深度学习医疗AI最新文献
  • vanna多表关联的实验
  • 英一真题阅读单词笔记 10年
  • Meta发布V-JEPA 2世界模型及物理推理新基准,推动AI在物理世界中的认知与规划能力
  • RED DA认证-EN18031网络安全常见问题以及解答
  • supervisorctr命令简介
  • 国外网站页头设计图片/湖南正规关键词优化首选
  • 网站建设面对的问题/企业网站制作模板
  • 免费的小网站/网站搜索优化价格
  • 淄博学校网站建设报价/seo网站优化培训找哪些
  • 怎么设计网站页面/人民日报新闻消息
  • 做佛像在什么网站发贴效果好点/广东vs北京首钢