剑指OFFER笔记_11_旋转数组的最小数字_JAVA实现
题目:旋转数组的最小数字
- 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
解题思路
- 可以用从头到尾遍历一次找到最小值,时间复杂度为O(n)。
- 旋转数组可以看作是两个排序的数组,其中第一个数组的最小值大于后一个数组的最大值。而最小数字就是后一个数组的第一个元素。所以我们只要找到两个数组的分界元素,就可以找到最小数字。
- 如果利用二分法查找,那么时间复杂度将是O(logN)。
- 用high和low分别存储当前范围的和数组下标的上下限。mid=(low+high)/2指向中间的元素。
- 如果num[mid]<num[low],说明分界在mid的左边,也就是下次检索的范围是low到mid,所以high=mid。如果num[mid]>num[low],说明分界在mid的右边,也就是下次检索的范围是mid到high,所以low=mid。
- 直到low和high为相邻的元素,说明low指向前一个数组的最大元素,high指向后一个数组的最小元素。
- 我们还需要考虑一些特殊情况:数组中存在一些相等的元素,如果low、mid、high指向的元素全部相同,我们就无法判断下一次检索的范围应该是什么,此时只能采取从头到尾该范围的遍历算法了。
- 还有一种特殊情况,数组旋转了0次,此时两个缩小范围的判断条件的都不符合,第一个元素就是我们要找的值。
- 综合以上的思路和特殊情况处理,可以写出如下代码:
代码
函数主体部分代码
package q11;
public class Solution {
public int minArray(int[] numbers) {
//异常处理
if(numbers == null || numbers.length == 0)
{
return -1;
}
//low用来控制范围的下限
//high用来控制范围的上限
//mid为中值
int low = 0;
int high = numbers.length-1;
int mid = (low + high) / 2;
//旋转次数为0的特殊情况,第一个元素即为最小元素
if(numbers[low] < numbers[high])
{
return numbers[0];
}
//此时旋转次数一定不为0
//结束条件是两个下标相邻。
while(low < high - 1)
{
mid = (low + high) / 2;
//如果出现low、high、mid相等的情况无法继续判断,只能顺序检测
if(numbers[low] == numbers[high] && numbers[low] == numbers[mid])
{
return MinInOrder(numbers, low, high);
}
//如果mid的数小于low的数,则说明最小的数字在low和mid之间,所以把mid赋值给high
if(numbers[mid] < numbers[low])
{
high = mid;
continue;
}
//如果mid的数大于high的数,则说明最小的数字在mid和high之间,所以把mid赋值给low
if(numbers[mid] > numbers[high])
{
low = mid;
continue;
}
}
//当low和high相邻时,右边的high就是最小数。
return numbers[high];
}
/**
* 用顺序遍历的方法去寻找最小数
* @param numbers
* @param low
* @param high
* @return
*/
public int MinInOrder(int[] numbers, int low, int high)
{
if(numbers == null || numbers.length == 0)
{
return -1;
}
int min = numbers[low];
for (int i = low; i <= high; i++)
{
if(numbers[i] < min)
{
min = numbers[i];
}
}
return min;
}
}
测试部分代码
package q11;
public class TestApp {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] nums1 = null;
int[] nums2 = {};
int[] nums3 = {2,2,0,2,2,2,2};
int[] nums4 = {1,2,3,4,5,6,7};
int[] nums5 = {3,4,5,6,1,2};
Solution s = new Solution();
System.out.println("The min value in nums1[] is:" + s.minArray(nums1));
System.out.println("The min value in nums2[] is:" + s.minArray(nums2));
System.out.println("The min value in nums3[] is:" + s.minArray(nums3));
System.out.println("The min value in nums4[] is:" + s.minArray(nums4));
System.out.println("The min value in nums5[] is:" + s.minArray(nums5));
}
}
运行结果截图
LeetCode运行截图