LeetCode链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/
题目:
假设按照升序排序的数组在某个未知的点上进行了旋转,例如,数组[0, 1, 2, 4, 5, 6, 7]可能变为[4, 5, 6, 7, 0, 1, 2]
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回-1;
可以假设数组中不存在重复元素,要求算法的时间复杂度必须是O(log n)级别;
我的想法是:先找到旋转点,再找目标值target在数组中的索引。这两个查找过程均使用二分查找,时间复杂度为O(log n);
如果一个有序数组发生了旋转,整体上将不再有序,但是会得到两个部分有序的子数组,如上例中的[4, 5, 6, 7]和[0, 1, 2]这两个部分仍是有序的,所以可以使用二分查找,找到旋转点,旋转点也就是两个有序子数组的分界点;
找到旋转点后再将target的值与nums[旋转点]的值进行比较,选择在哪个有序子数组里使用二分查找寻找target所对应的索引值
1 public class Solution { 2 public int search(int[] nums, int target) { 3 if(nums == null || nums.length == 0) return -1; 4 if(nums.length == 1) return nums[0] == target ? 0 : -1; 5 int left = 0, right = nums.length - 1, mid = 0; 6 // 先找到旋转点,旋转点也就是两个有序子数组的分界点 7 int rotateIndex = findRotateIndex(nums); 8 if(nums[left] > nums[right]) { // 判断nums是否发生了旋转,如果发生了,那么判断应该在哪个有序子数组里查找 9 if(target >= nums[left]) { 10 right = rotateIndex; 11 }else { 12 left = rotateIndex + 1; 13 } 14 } 15 while(left <= right) { // 在有序子数组中查找目标值的索引 16 mid = (left + right) / 2; 17 if (target > nums[mid]) { 18 left = mid + 1; 19 } 20 else if(target < nums[mid]){ 21 right = mid - 1; 22 } 23 else { 24 return mid; 25 } 26 } 27 return -1; 28 } 29 30 public int findRotateIndex(int[] nums) { // 查找旋转点的下标 31 int left = 0, right = nums.length - 1, mid = 0; 32 if(nums[left] <= nums[right]) return right; 33 int rotateIndex = right; // 记录旋转点,它始终指向的是数组元素的最大值 34 while(left <= right) { 35 if(nums[left] <= nums[right]) { // 当条件成立时,说明该子数组是有序子数组,即找到了两个有序子数组的分界点 36 rotateIndex = right < mid ? right : left - 1; 37 return rotateIndex; 38 } 39 else { 40 mid = (left + right) / 2; 41 if(nums[left] <= nums[mid]) { 42 left = mid + 1; // 说明旋转点在mid的右边 43 } 44 else { 45 right = mid - 1; // 说明旋转点在mid的左边 46 } 47 } 48 } 49 return rotateIndex; 50 } 51 }