求:
搜索旋转数组。给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次了,次数不详。请编写代码找出数组中的某个元素,假设数组元素原先是按升序排列的。若有多个相同元素,返回索引值最小的一个。
示例1:
输入: arr = [15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14], target = 5
输出: 8(元素5在该数组中的索引)
示例2:
输入:arr = [15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14], target = 11
输出:-1 (没有找到)
提示:
arr 长度范围在[1, 1000000]之间
题目链接: https://leetcode-cn.com/problems/search-rotate-array-lcci/
解:
1、二分搜索子数组
因为要求返回的是与target相等的数组元素的最小索引,因此想到从左往后搜索,将旋转数组拆分为若干个有序的子数组,然后对每个子数组进行二分搜索,如果能够找到与target相等的元素,还需要考虑重复的问题,因此要向前遍历,直到找到索引最小的与target相同的元素。如果找不到与target相等的元素,返回-1。
时间复杂度:O(NlogN)
空间复杂度:O(1)
public int search(int[] arr, int target) { int start, end, ret; for (start = 0, end = 0; end < arr.length - 1; ++end) { if (arr[end + 1] < arr[end]) { ret = binarySearch(arr, target, start, end); if (ret != -1){ while(ret>0 && arr[ret-1]==target) --ret; return ret; } else start = end+1; } } ret = binarySearch(arr, target, start, end); if (ret != -1){ while(ret>0 && arr[ret-1]==target) --ret; return ret; } return -1; } private int binarySearch(int arr[], int target, int start, int end) { int low = start; int high = end; while (low <= high) { int mid = (low + high) / 2; if (arr[mid] == target) return mid; else if (arr[mid] < target) low = mid + 1; else high = mid - 1; } return -1; }
2、二分搜索旋转数组
最优解,直接对旋转数组进行二分搜索,在二分搜索内部进行分支判断,修正左右端点。因为题目中的数组长度很大,当数组长度很大时,该方法明显优于方法1。
时间复杂度:O(logN),最坏情况每个元素都需要遍历,为O(N)
空间复杂度:O(1)
public int search(int[] arr, int target) { int len = arr.length; int left = 0, right = len - 1; while (left < right) { int mid = left + (right - left) / 2; if (arr[mid] < arr[right]) { if (arr[mid] < target && (target < arr[right] || (target == arr[right] && arr[left] != target))) { left = mid + 1; } else { right = mid; } } else if (arr[mid] > arr[right]) { if (arr[mid] < target || target < arr[right] || (target == arr[right] && arr[left] != target)) { left = mid + 1; } else { right = mid; } } else { right--; } } return arr[left] == target ? left : -1; }
来源:oschina
链接:https://my.oschina.net/u/4469818/blog/4338446