大家好今天给大家分享下一道 LeetCode 中等难度 的题目[面试题 10.03. 搜索旋转数组](leetcode-cn.com/problems/co…)
这里主要是分享思路和注释,供大家更好的理解题目解法,代码部分是参考LeetCode 转写成javascript 代码,
题目
搜索旋转数组。给定一个排序后的数组,包含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 (没有找到)
分析
1.查找元素类题目
2.数组是排序后的选择的,所以肯定是部分有序,于是为了缩减时间复杂度 我们可以采用二分查找
采用的方法是
1.暴力法
2.二分查找
解法一: 暴力法
思路
1.直接查找元素
2.找到的一个元素肯定是最左边的元素
(如果面试肯定是过不到的, 只是提供思路的一种)
var search = function (arr, target) {
for (let i = 0; i < arr.length; i++) {
// 找到的第一个元素是最左边的
if (arr[i] === target) {
return i;
}
}
return -1;
};
/* 复杂度
时间 O(n)
空间 O(1)
*/
解法二:二分查找
代码部分参考 leetcode-cn.com/problems/se…
思路
1.首先判断那边是有序数组 还是在无序数组那边,
如果是有序数组比较target是否在 有序数组的最左边的值和右边的值之间,如果存在,则缩小范围到左边的数组中
这里需要注意:如果不是,则还是有可能在左边的数组中,因为我们的题目是找最左索引,所以要尽最大可能在左边找,
2.因为存在重复的值,所以需要多一步判断有序数列的时候要注意判断是遇到了重复的值 还是遇到了答案
var search = function (arr, target) {
let l = 0,
r = arr.length - 1;
while (l <= r) {
// 求取中间的值
const mid = Math.floor(l + (r - l) / 2);
// 如果左边的是有序数列
if (arr[l] < arr[mid]) {
// 如果在有序数列中,则缩小范围到左边的数组中
if (arr[l] <= target && target <= arr[mid]) {
r = mid;
} else {
l = mid + 1;
}
// 如果右边的有序数列,则还是在左边找,
} else if (arr[l] > arr[mid]) {
//因为是旋转后的升序数组,所以如果arr[l] <= target || target <= arr[mid],则有还是在左边数组中
if (arr[l] <= target || target <= arr[mid]) {
r = mid;
} else {
l = mid + 1;
}
// 如果遇到了 arr[l]===arr[mid],有2中情况,第一个遇到了相同的值例如 [3,3,3,5],第二种情况找到了答案
} else {
// 找到了答案
if (arr[l] === target) {
return l;
// 过滤掉重复值 继续下一轮循环
} else {
l++;
}
}
}
return -1;
};
/* 复杂度
时间 O(logN)
空间 O(1)
*/
总结
这道题,需要的前置知识是二分查找,因为二分查找的时间复杂度是 O(logn),比循环的O(n)都还小, 所以对算法提高性能有很大帮助,大家可以尝试多多练习。
大家可以看看我分享的一个专栏(前端搞算法)里面有更多关于算法的题目的分享,希望能够帮到大家,我会尽量保持每天晚上更新,如果喜欢的麻烦帮我点个赞,十分感谢
文章内容目的在于学习讨论与分享学习算法过程中的心得体会,文中部分素材来源网络,如有侵权,请联系删除,邮箱 182450609@qq.com