假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7]
可能变为 [4,5,6,7,0,1,2]
)。
请找出其中最小的元素。
你可以假设数组中不存在重复元素。
示例 1:
输入: [3,4,5,1,2]
输出: 1
示例 2:
输入: [4,5,6,7,0,1,2]
输出: 0
题目分析:
数组是升序排列的,且其中没有重复元素,只是有可能会在某个点上旋转,要求数组中的最小值。
涉及到排序的数组查找值,首先想到二分查找。
- 如果这个旋转数组只有一个数直接返回这个数;
- 如果这个旋转数组的第一个数小于数组的最后一个数,那么说明旋转数组本身就是升序的,也就是说没有进行旋转,直接返回第一数;
- 而对于其他情况,采取二分查找的思想进行查找,当在二分的过程中,找到这样的一个数(这个数既比它的左边的数下,又比它右边的数小),那么就是最小的数直接返回即可;
- 如果在循环结束以后没有找到,说明肯定是在边界,因为最小值如果在中间,那么必然已经经过了判断直接返回了结果,所以这个时候只需要比较数组的第一个数和最后一个数。
代码实现:
public int findMin(int[] nums) { if (nums.length == 1) return nums[0]; if (nums[0] < nums[nums.length - 1]) return nums[0]; int left = 0; int right = nums.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if ((mid + 1) < nums.length && nums[mid] < nums[mid + 1] && nums[mid] < nums[mid - 1]) return nums[mid]; else if (left >= 1 && (left + 1) < nums.length && nums[left] < nums[left - 1] && nums[left] < nums[left + 1]) return nums[left]; else if (right >= 1 && (right + 1) < nums.length && nums[right] < nums[right - 1] && nums[right] < nums[right + 1]) return nums[right]; else if (nums[mid] > nums[0]) left = mid + 1; else right = mid - 1; } return nums[0] < nums[nums.length - 1] ? nums[0] : nums[nums.length - 1]; }
主函数:
public static void main(String[] args) { S3 s = new S3(); int[] res1 = new int[]{3,4,5,1,2}; int[] res2 = new int[]{4,5,6,7,0,1,2}; int[] res3 = new int[]{2,1}; System.out.println(s.findMin(res1)); System.out.println(s.findMin(res2)); System.out.println(s.findMin(res3)); }
运行结果:
1
0
1