二分查找的思想是:
- 从数组的中间位置开始,如果中间元素正好是目标元素,则结束搜索;
- 如果目标值大于或小于中间元素,则在大于或小于中间元素的那一半数组中搜索;
- 重复1、2步;若未找到,return -1;
二分查找用在有序数组中。
二分查找的使用场景:查找一个数字;统计某个数字出现的次数。
分而治之是算法设计中的一种方法。它将一个问题分成多个和原问题相似的小问题,递归解决小问题,再将结果合并以解决原来的问题。分而治之适用的场景:归并、快速、二分和反转二叉树。
题目要求
题目分析
题目中给出的是半有序数组,仍然可以用二分查找。那中间元素和左、右哪个位置比较呢?
比如:[1,2,3,4,5] 和 [3,4,5,1,2],中间位置都比左位置元素大,第一个数组最小位置在左边,第二个在右边,所以跟左边比较得不出答案。但是跟右位置比较,第一个数组可以得出在左边,第二个在右半边。所以,用中间位置元素和右位置元素比较。
步骤
- 设置左右位置元素;
- 中间位置元素依次和右边元素位置对比;
- 中间位置元素小于右边元素,区间为[ left,mid ];
- 中间位置元素大于右边元素,区间为[ mid+1,high ];
- 中间元素和最右边元素相同,只能把最右边排出掉,区间为[ high-- ]。
Code part
var minArray = function(numbers) {
if(!numbers.length) return 0;
let low = 0;
let high = numbers.length - 1;
while(low < high){
const mid = Math.floor((low + high) / 2); //注意mid的位置,求每次移动后的mid位置,所以在while里面
if(numbers[mid] > numbers[high]){
//说明最小元素在mid右边,且mid元素比最右边大
//所以下一轮搜索区间为[mid+1,right]
low = mid + 1;
}else if(numbers[mid] < numbers[high]){
//mid 右边的元素一定不是最小数字,mid有可能是,
//所以下一轮搜索区间为[low,mid]
high = mid;
}else{
//中间元素和最右边元素相同,只能把最右边排出掉,
//下一轮搜索区间为[left,high-1]
high--
}
}
return numbers[low]//最小数字一定在数组中,不管low,high如何移动,每动一次,low永远是区间内最小数字
};