问题:
Suppose a sorted array 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.
代码示例:
1、这个问题并不困难,如果不用高级的数据结构,主要思路就是:
重新调整数组,使之有序。
然后在有序的数组中,找出target值对应的index。
然后,将该index映射成原数组的值。
194个测试用例,耗时17ms。
缺点是细节太多,第一次觉得写测试用例,比写代码本身还有难度。
public class Solution {
public int search(int[] nums, int target) {
if (nums == null || nums.length < 1) {
return -1;
}
if (nums.length == 1) {
if (nums[0] != target) {
return -1;
} else {
return 0;
}
}
//判断数组如果没有rotated,是否是升序
boolean asc = isAsc(nums);
//找到出现rotated的位置
//如果没有rotated,那么pivotIndex的值为0
int pivotIndex = getPivotIndex(nums, asc);
//getNewArray将rotated的数组,变换成有序数组
//就是将pivot~length-1的数字,平移到0~length-1-pivot
//将0~pivot平移到length-pivot~length-1
//然后,在有序数组中找到index
int result = getIndex(getNewArray(nums, pivotIndex), 0, nums.length-1, asc, target);
//没找到坐标,或没发生平移,直接返回结果
if (result != -1 && pivotIndex != 0) {
//按上面的平移规则,逆向得到原下标
int len = nums.length - 1 - pivotIndex;
if (result <= len) {
result = result + pivotIndex;
} else {
result = result + pivotIndex - nums.length;
}
}
return result;
}
private static boolean isAsc(int[] nums) {
if (nums.length == 2) {
return nums[0] < nums[1];
}
boolean result = false;
//这个就不细说了,大家将可能的情况画个图就能明白
if (nums[0] < nums[1]) {
if (nums[1] < nums[2]) {
result = true;
} else if (nums[0] > nums[nums.length-1]) {
result = true;
}
} else if (nums[1] < nums[2] ){
result = true;
}
return result;
}
//找到第一个不符合顺序的点
private static int getPivotIndex(int[] nums, boolean asc) {
int pivotIndex = 0;
if (asc) {
for (int i = 0; i < nums.length - 1; ++i) {
if (nums[i + 1] < nums[i]) {
pivotIndex = i + 1;
break;
}
}
} else {
for (int i = 0; i < nums.length - 1; ++i) {
if (nums[i+1] > nums[i]) {
pivotIndex = i + 1;
break;
}
}
}
return pivotIndex;
}
//构造新的有序数组
private static int[] getNewArray(int nums[], int pivotIndex) {
if (pivotIndex == 0) {
return nums;
}
int[] newArray = new int[nums.length];
int j = 0;
for (int i = pivotIndex; i < nums.length; ++i) {
newArray[j] = nums[i];
++j;
}
for (int i = 0; i < pivotIndex; ++i) {
newArray[j] = nums[i];
++j;
}
return newArray;
}
//二分法,结合排序方式,递归查找结果
private static int getIndex(int nums[], int beginIndex, int endIndex, boolean asc, int target) {
if (beginIndex > endIndex) {
return -1;
}
int middle = (beginIndex + endIndex) / 2;
if (nums[middle] == target) {
return middle;
} else if (middle == beginIndex && middle == endIndex) {
return -1;
} else {
if (((nums[middle] > target) && asc)
|| (nums[middle] < target && !asc)){
return getIndex(nums, beginIndex, middle-1, asc, target);
} else {
return getIndex(nums, middle + 1, endIndex, asc, target);
}
}
}
}
2、HashMap无脑求解
思路就不用解释了。
194个测试用例,耗时19ms。
缺点:稍微耗时一点,有种拿着神器作弊的感觉。。。
public class Solution {
public int search(int[] nums, int target) {
if (nums == null || nums.length < 1) {
return -1;
}
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; ++i) {
map.put(nums[i], i);
}
if (map.containsKey(target)) {
return map.get(target);
} else {
return -1;
}
}
}
3、新的题目描述中,定义原数组是升序的,直接二分法即可。
class Solution {
public int search(int[] nums, int target) {
if (nums == null || nums.length < 1) {
return -1;
}
if (nums.length == 1) {
return target == nums[0] ? 0 : -1;
}
int leftIndex = 0;
int rightIndex = nums.length - 1;
while (leftIndex <= rightIndex) {
int midIndex = (leftIndex + rightIndex) / 2;
int middleValue = nums[midIndex];
if (middleValue == target) {
return midIndex;
}
//Middle处于第一段上升沿
if (nums[0] <= middleValue) {
if (target >= nums[0] && target < middleValue) {
rightIndex = midIndex - 1;
} else {
leftIndex = midIndex + 1;
}
//Middle处于Rotate上升沿
} else {
if (target > middleValue && target <= nums[nums.length - 1]) {
leftIndex = midIndex + 1;
} else {
rightIndex = midIndex - 1;
}
}
}
return -1;
}
}