题目链接
题目
函数接口
题解
抛开该数组为一个旋转数组这点。本题的实质就是在一个数组中找到最小数字。
一个很简单的方式就是对数组进行排序,使得数组为一个升序数组,然后输出数组第一项即可。
思路一
对整个数组进行升序排序,然后返回数组第一项。因为整个数组第一项(即整个数组的最小项)必然也是旋转数组的最小项。
实现代码如下
public int minNumberInRotateArray(int[] array) {
if (array.length == 0 || array == null)
return 0;
Arrays.sort(array);
return array[0];
}
思路一这种方法虽然简单易行,代码量少。但因为利用了快排,所以时间复杂度为O(NlogN),因为计算过程中的许多排序操作,对于解题本身的意义并不大,所以产生了很多不必要的开销。
回想一下在学校时,在一个数组中查找最大/最小值的方法。不难想起一简单种易行,且时间复杂度为O(N)的方法。
思路二
在学校学习时,在一个有序/无序数组中查找最大/最小值的方法。最简单的一种,就是遍历整个数组,这样的时间复杂度也不过是O(N)。
但是对于该题,结合旋转数组的性质,笔者对于这种思路进行了一点小的调整。
首先对问题进行归约,对于一个朴素的旋转数组(即不存在重复的数组,且已经存在若干个元素的旋转),那么从后往前遍历。那么数值必然是先递减,再在某个位置断崖式的上升,然后再递减。
例如:4 5 6 7 8 9 10 1 2 3
3到1时是递减,然后在10这个位置上升,10到4继续保持递减。
不难发现,如果是这种情况,那么那个上升点的位置(本例中即是1),即是旋转数组最小的数字。
那么我们再对问题进行推广
对于一个非朴素的旋转数组(包含重复数字,或没有元素旋转)
给出以下三个样例:
1 2 2 2 3 3 3 1 1
1 1 1 1 1 1 1 1 1
1 2 3 4 5 6 7 8 9
不难发现,最小数字所处位置都是在数组第一项。
将以上的推论进行整理,即可得出思路二的一个实现
public int minNumberInRotateArray(int[] array) {
if (array.length == 0 || array == null)
return 0;
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1]) {
return array[i];
}
}
return array[0];
}
思路三
思路二相比思路一,在时间复杂度和辅助空间复杂度上都有所提升(块排采用递归实现,栈的使用和断点信息的保存都会带来空间和时间的开销)。
相比而言,思路二已经是较为可行的一种思路。
那么还有没有一种方法可以继续降低时间复杂度呢?
先回想一下,如果时间开销要比O(N)更低,那么常见的就有O(根号N),O(logN),O(1)。
对于笔者,看到O(logN)这个复杂度,第一反应就是二分法,那么对于本题。是否可以采用二分法呢?
答案是可以的
同样先对问题进行归约,对于一个朴素的旋转数组
例如:4 5 6 7 8 9 1 2 3
首先取得其中项8,若中项大于末项。那么就对后半段进行下一步操作。
得:9 1 2 3
其中项是1,由于中项小于末项,那么就对前半段进行操作。
得:9 1
同理,其中项是9,中项大于末项,继续对后半段进行操作。
得:1
由于只剩一个元素,所以该元素就是问题答案。
那么我们对于问题进行推广,同样采用以下三组样例:
1 2 2 2 3 3 3 1 1
1 1 1 1 1 1 1 1 1
1 2 3 4 5 6 7 8 9
简单进行一下模拟,发现同样能得到正解。
对于以上思路进行归纳整理,得到该思路的一个实现
public int minNumberInRotateArray(int[] array) {
if (array.length == 0 || array == null)
return 0;
int index = binarySearchMinNumber(0, array.length - 1, array);
return array[index];
}
public int binarySearchMinNumber(int left, int right, int[] array) {
int mid = (left + right) / 2;
if (left == right) {
return left;
} else if (array[mid] > array[right]) {
return binarySearchMinNumber(mid + 1, right, array);
} else {
return binarySearchMinNumber(left, mid, array);
}
}
以上三种思路是笔者对于本题的一些简单思考。如果有更优异的解法,欢迎大家分享。