问题描述
给定一个无重复整数的升序的循环数组(例如:[1,2,3,4,5] 或 [4,5,6,1,2,3]),要求以O(log n)的时间复杂度查找一个数字是否在这个数组中,如果存在,则返回该数字的下标,否则返回-1。题目链接:**点我**
样例输入输出
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
输入:nums = [1,2,3,4,5], target = 0
输出:-1
问题解法
此题要求以O(log n)的时间复杂度进行求解,只有二分查找才能满足要求。但是二分查找要求的前提条件是数组有序,而此题数组的“有序”是可循环的,即数组从某个位置开始向右遍历回到此位置,这之间经过的数字是有序的。因此,只需要求出数组最小值的位置,记录此偏移量,然后在二分查找的比较中,用计算得到的中间下标位置加上偏移量得到真正的数组的中间下标位置,然后跟目标值进行比较,其他步骤跟二分查找一样,即可得到问题的答案。代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| class Solution {
private int getOffsetNum(int[] nums) { int result = 0; int length = nums.length; int i = 0; int j = length - 1; while (i <= j) { int middle = (i + j) / 2; if (nums[middle] > nums[(middle + 1) % length]) { result = middle + 1; break; } if (nums[middle] > nums[length - 1]) { i = middle + 1; } else { j = middle - 1; } } return result; } public int search(int[] nums, int target) { int offsetNum = getOffsetNum(nums); int i = 0; int j = nums.length - 1; int result = -1; while (i <= j) { int middle = (i + j) / 2; int realMiddleIndex = (middle + offsetNum) % nums.length; if (nums[realMiddleIndex] == target) { result = realMiddleIndex; break; } if (nums[realMiddleIndex] < target) { i = middle + 1; } else { j = middle - 1; } } return result; } }
|