查找和排序
tips:
在面试时,如果面试官要求实现一个排序算法,那么一定要问清楚这个排序应用的环境是什么、有哪些约束条件。
数组在一定程度上是排序的,很容易分析出:可以采用二分法来寻找最小数字。
题目
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组 {3, 4, 5, 1, 2} 为 {1, 2, 3, 4, 5} 的一个旋转,该数组的最小值为1。
思路
数组在一定程度上是排序的,很容易分析出:可以采用二分法来寻找最小数字。
但是这里面有一些陷阱:
递增排序数组的本身是自己的旋转,则最小数字是第一个数字
中间数字 与 首尾数字 大小相等,如 {1, 0, 1, 1, 1, 1} 和 {1, 1, 1, 1, 0, 1},无法采用二分法,只能顺序查找。
测试用例
- 功能测试(正常旋转数组,中间有或者无重复数字)
- 边界值测试(升序数组,1个数字的数组)
- 特殊输入测试(null,空数组)
Java代码
1 | public class MinNumberInRotateArray { |
下面是测试代码。
1 | public class MinNumberInRotateArray { |
牛客网优秀代码
1 | public class Solution{ |
这段代码的细节:
- 使用low = mid + 1,而不是low = mid,最终会使得low = high(左右指针重合)而跳出循环。
- 使用high = mid,而不是high = mid - 1,因为mid有可能就是最小值点,不能减1。
- 升序数组的情况可以直接在循环中一起搞定,不用单独列出来判断。
不好的地方:
该程序在array[mid] = array[high]时直接顺序查找。但其实这还有可能可以用二分法的,除非还满足array[mid] = array[low],才只能使用顺序查找。
所以可以先排除掉必须顺序查找的情况(类似自己上面的程序,提前判断掉),之后就可以直接删除else if(array[mid] == array[high]){high = high - 1;这两行了。缺少null的判断。
总结
- 题目中给定的特殊条件一定要去关注,往往就是解法的题眼,尤其是接触到一个新的概念时,要能快速理解并考虑全面。
- 要注意一些特例,如递增数组的本身是自己的旋转、相同数字数组。
- 如果数组一定程度上是排序的,可以考虑使用二分法来解题。对于数组的方法(如二分法等),可以用low、high、mid或者left、right、mid来表示左右指针,也即数组下标。