1. 题目
https://leetcode.cn/problems/search-in-rotated-sorted-array/
考察点
这道题的考察点是二分查找的应用。二分查找是一种在有序数组中查找目标值的高效算法,它的时间复杂度是O(log n)。二分查找的基本思想是,每次比较中间元素和目标值的大小,根据比较结果缩小搜索范围,直到找到目标值或者搜索范围为空。
这道题的难点是,给定的数组不是完全有序的,而是在某个点旋转过的。这就需要我们先找到旋转点,然后根据目标值和数组最后一个元素的大小关系,确定搜索范围是在旋转点的左边还是右边。这两个步骤都可以用二分查找来实现。最后,在搜索范围内用二分查找来找到目标值。
这道题考察了我们对二分查找的理解和灵活运用
2. 解法
思路
LeetCode 33题是在一个旋转有序数组中搜索一个目标值,如果找到了返回它的索引,否则返回-1。要求算法的时间复杂度是O(log n)。
你可以用二分查找的思想来实现这个问题。首先,找到数组中的最小值的索引,这个索引就是旋转的点。然后,根据目标值和数组的最后一个元素的大小关系,确定搜索的范围是在旋转点的左边还是右边。最后,在搜索的范围内用二分查找来找到目标值。
代码逻辑
- 首先,我要找到数组中的最小值的索引,这个索引就是旋转的点。我用二分查找的方法来找,比较中间元素和最后一个元素的大小,如果中间元素大于最后一个元素,说明最小值在右半部分,否则在左半部分。这样不断缩小搜索范围,直到找到最小值的索引。
- 然后,我要确定搜索目标值的范围是在旋转点的左边还是右边。我用目标值和数组的最后一个元素的大小关系来判断,如果目标值小于等于最后一个元素,说明目标值在旋转点右边的升序部分,否则在左边的升序部分。这样我就可以确定搜索范围的起始和结束位置。
- 最后,在搜索范围内用二分查找来找到目标值。比较中间元素和目标值的大小,如果相等就返回索引,如果中间元素小于目标值,说明目标值在右半部分,否则在左半部分。这样不断缩小搜索范围,直到找到目标值或者搜索范围为空。
具体实现
public class Solution { public int search(int[] nums, int target) { if (nums == null || nums.length == 0) { return -1; } int minIdx = findMinIdx(nums); //找到旋转点 if (target == nums[minIdx]) { return minIdx; } int m = nums.length; int start = (target <= nums[m - 1]) ? minIdx : 0; //确定搜索范围 int end = (target > nums[m - 1]) ? minIdx : m - 1; while (start <= end) { //二分查找 int mid = start + (end - start) / 2; if (nums[mid] == target) { return mid; } else if (target > nums[mid]) { start = mid + 1; } else { end = mid - 1; } } return -1; } private int findMinIdx(int[] nums) { //找到旋转点 int start = 0; int end = nums.length - 1; while (start < end) { int mid = start + (end - start) / 2; if (nums[mid] > nums[end]) { start = mid + 1; } else { end = mid; } } return start; } }