持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第26天,点击查看活动详情
面试题 10.03. 搜索旋转数组
搜索旋转数组。给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次了,次数不详。请编写代码找出数组中的某个元素,假设数组元素原先是按升序排列的。若有多个相同元素,返回索引值最小的一个。
「示例1:」
输入: arr = [15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14], target = 5
输出: 8(元素5在该数组中的索引)
「示例2:」
输入:arr = [15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14], target = 11
输出:-1 (没有找到)
「提示:」
arr 长度范围在[1, 1000000]之间
解题思路
// 第一种
先找到遍历的位置,如果target比数组的第一位大,肯定就在数组前面一点,从后往前遍历
如果target比数组第一位小,就从后往前遍历
从前往后遍历的时候,找到target就返回,直到遍历到第一个比target大的数字,退出遍历
从后往前遍历的时候,找到和target一样的数字的时候,更新结果下标,直到第一个比target小的数字,退出循环
// 第二种
数组一定是两段分别递增
在两段上分别用二分搜索查找
先找左边的段,再找右边的段(方便返回最小的索引)
代码实现
/**
* @param {number[]} arr
* @param {number} target
* @return {number}
*/
var search = function(arr, target) {
const len = arr.length
if (target >= arr[0]) {
// 从前往后
let l = 0
while(l < len) {
if (arr[l] === target) return l
if (arr[l] > target) break
l++
}
return -1
} else {
// 从后往前
let l = len - 1, res = -1
while (l >= 0) {
if (arr[l] === target) res = l
if (arr[l] < target) break
l--
}
return res
}
};
// 第二种
var search = function(arr, target) {
// 二分搜索写成模板方便调用,查找左边界的二分搜索
var biSearch = function(left, right){
while(left <= right){
let mid = left + ((right - left)>>1);
if(arr[mid] >= target){
right = mid - 1;
} else {
left = mid + 1;
}
}
return arr[left]===target? left : -1;
}
// 找到中间的断点区分两段
let point = 0
for(let i = 0; i < arr.length-1;i++){
if(arr[i] <= arr[i+1]){
point++;
} else break;
}
// 左边进行二分搜索
let leftRes = biSearch(0, point);
if(leftRes!== -1) return leftRes; // 左边找到了就返回
else { // 左边没找到就找右边
let rightRes = biSearch(point+1, arr.length -1)
return rightRes;
}
};
如果你对这道题目还有疑问的话,可以在评论区进行留言;