二分查找【零神基础精讲】
来源0x3f:https://space.bilibili.com/206214
文章目录
- 二分查找
- [34. 在排序数组中查找元素的第一个和最后一个位置](https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/)
- [162. 寻找峰值](https://leetcode.cn/problems/find-peak-element/)
- [153. 寻找旋转排序数组中的最小值](https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/)
- [33. 搜索旋转排序数组](https://leetcode.cn/problems/search-in-rotated-sorted-array/)
二分查找
34. 在排序数组中查找元素的第一个和最后一个位置
难度中等2147
给你一个按照非递减顺序排列的整数数组 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
class Solution {public int[] searchRange(int[] nums, int target) {if(nums.length == 0) return new int[]{-1,-1};int left = 0,right = nums.length-1;while(left <= right){int mid = (left+right)/2;if(target <= nums[mid]) right = mid -1;else left = mid +1; } //right返回位置为target最左侧-1if((right+1) == nums.length || nums[right+1] != target) return new int[]{-1,-1};int end = right+1;while (end < nums.length && target == nums[end]) end++;return new int[]{right+1,end-1};}
}
162. 寻找峰值
难度中等982
峰值元素是指其值严格大于左右相邻值的元素。
给你一个整数数组 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.length <= 1000
-231 <= nums[i] <= 231 - 1
- 对于所有有效的
i
都有nums[i] != nums[i + 1]
class Solution {public int findPeakElement(int[] nums) {int res = 0;int n = nums.length;int left = 0, right = n;while(left < right){int mid = (left + right) >> 1;if(mid < n-1 && nums[mid] < nums[mid+1]) left = mid+1;else right = mid;}return right;}
}
153. 寻找旋转排序数组中的最小值
难度中等908
已知一个长度为 n
的数组,预先按照升序排列,经由 1
到 n
次 旋转 后,得到输入数组。例如,原数组 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
原来是一个升序排序的数组,并进行了1
至n
次旋转
class Solution {public int findMin(int[] nums) {int n = nums.length;int left = 0, right = n;int res = 0;while(left < right){int mid = (left + right) >> 1;if(mid < n-1 && nums[mid] < nums[mid+1]) right = mid;else left = mid+1;}return nums[left];}
}
33. 搜索旋转排序数组
难度中等2489
整数数组 nums
按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums
在预先未知的某个下标 k
(0 <= 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
class Solution {public int search(int[] nums, int target) {int n = nums.length;int left = 0, right = n;while(left < right){int mid = (left + right) >> 1;if(nums[mid] == target) return mid;// 左边有序if(nums[left] < nums[mid]){// 判断target是否在区间内,是则缩小右边界if(nums[left] <= target && target <= nums[mid]){right = mid;}else{left = mid+1;}}// 左边有序else{// 判断target是否在区间内,是则扩大左边界if(nums[mid] <= target && target <= nums[right-1]){left = mid+1;}else{right = mid;}}}return -1;}
}