题目:在翻转有序中搜索
难度:Medium
题目内容:
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., [0,1,2,4,5,6,7]
might become [4,5,6,7,0,1,2]
).
You are given a target value to search. If found in the array return its index, otherwise return -1
.
You may assume no duplicate exists in the array.
Your algorithm's runtime complexity must be in the order of O(log n).
翻译:
假设一个按升序排序的数组在事先不知道旋转点的情况下翻转。
(即。0,1,2,4,5,6,7可能变成4,5,6,7,0,1,2)。
您获得了搜索的目标值。如果在数组中找不到它的索引,否则返回-1。
数组中不存在重复。
您的算法的运行时复杂度应该为O(log n)
我的思路:要复杂度O(log n),但是数组只是基本有序,而排序算法的最佳情况也要O(N),本弱鸡想不出什么很好方法。。。
那就强行上吧,先插入排序一波,再二分法搜索。
然而最后要返回下标,再排序后下标会发生变化,所以再新建一个数组存储下标,在排序过程中,此数组相应的值跟着一起移动。
MyCode:
1 public int search(int[] nums, int target) { 2 int[] index = new int[nums.length]; 3 for (int i = 0; i < nums.length; i++) { 4 index[i] = i; 5 } 6 insertSort(nums, index); 7 return binaryFind(nums, target, index); 8 } 9 10 static int binaryFind(int[] nums, int target, int[] index) { 11 int low = 0; 12 int high = nums.length - 1; 13 while (low <= high) { 14 int mid = low + (high - low)/2; 15 if (nums[mid] == target) { 16 return index[mid]; 17 } else if (nums[mid] > target) { 18 high = mid - 1; 19 } else { 20 low = mid + 1; 21 } 22 } 23 return -1; 24 } 25 26 static void insertSort(int[] nums, int[] index) { 27 for (int i = 1; i < nums.length; i++) { 28 int temp = nums[i]; 29 int temp2 = index[i]; 30 int j = i - 1; 31 while (j > -1 && nums[j] > temp) { 32 nums[j+1] = nums[j]; 33 index[j+1] = index[j]; 34 j--; 35 } 36 nums[j+1] = temp; 37 index[j+1] = temp2; 38 } 39 }
我的算法复杂度:O(N2),因为插入排序的最坏情况就是O(N2)。
编码过程中出现的问题:
1、把插入排序的逻辑给忘了。。
答案代码:
1 public int search(int[] A, int target) { 2 int n = A.length; 3 int lo=0,hi=n-1; 4 while(lo<hi){ 5 int mid=(lo+hi)/2; 6 if(A[mid]>A[hi]) lo=mid+1; 7 else hi=mid; 8 } 9 int rot=lo; 10 lo=0;hi=n-1; 11 while(lo<=hi){ 12 int mid=(lo+hi)/2; 13 int realmid=(mid+rot)%n; 14 if(A[realmid]==target)return realmid; 15 if(A[realmid]<target)lo=mid+1; 16 else hi=mid-1; 17 } 18 return -1; 19 }
答案复杂度:O(logN)
答案思路:首先利用数组局部仍然有序的特点,和 A[mid]>A[hi] 的条件,以二分法定位到最小的那一个值的下标,注意当 A[mid]<=A[hi] 的时候,应该是hi=mid,因为此时的mid有可能就是最小点,所以不能放过。【当要求的点不是直接定位的mid的时候(等循环结束),mid 有可能就是最终的值,下一层的 lo 和 hi 的取值不能都把mid排除, 其中一个就是mid】
找到最小点后,记录下来,然后继续对原数组进行二分法搜索,然而,参与比较的mid应该改成realMid=(mid+rot)%n
以[4,5,6,7,0,1,2]为例,找到最小值(真起点)0的下标4后,取mid=(0+6)/2 = 3,而真正的中点下标应该等于(mid+rot)%n = (3+4)%7 = 0
之后的向左右移动是一样的,所以还是变化mid的值即可。