leetcode每日一题(2020-4-29):1095. 山脉数组中查找目标值
Posted autumn-starrysky
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode每日一题(2020-4-29):1095. 山脉数组中查找目标值相关的知识,希望对你有一定的参考价值。
题目描述:(这是一个#交互式问题#)
给你一个 山脉数组 mountainArr,请你返回能够使得 mountainArr.get(index) 等于 target 最小 的下标 index 值。如果不存在这样的下标 index,就请返回 -1。
何为山脉数组?如果数组 A 是一个山脉数组的话,那它满足如下条件:
首先,A.length >= 3
其次,在 0 < i < A.length - 1 条件下,存在 i 使得:
A[0] < A[1] < ... A[i-1] < A[i]
A[i] > A[i+1] > ... > A[A.length - 1]
你将 不能直接访问该山脉数组,必须通过 MountainArray 接口来获取数据:
MountainArray.get(k) - 会返回数组中索引为k 的元素(下标从 0 开始)
MountainArray.length() - 会返回该数组的长度
注意:
对 MountainArray.get 发起超过 100 次调用的提交将被视为错误答案。此外,任何试图规避判题系统的解决方案都将会导致比赛资格被取消。
为了帮助大家更好地理解交互式问题,我们准备了一个样例 “答案”:https://leetcode-cn.com/playground/RKhe3ave ,请注意这不是一个正确答案。
今日学习内容:
1.二分查找
2.在排序数组中查找元素的第一个和最后一个位置
3.位运算两数中点
1.二分查找:
二分查找要求:
1.必须采用顺序存储结构。
2.必须按关键字大小有序排列。
二分查找时间复杂度:
while循环的次数,即log(n)。
leetCode.704题(升序数组的二分查找)
非递归【参考了作者:oppeuro】:
var search = function(nums, target) {
var start = 0;
var end = nums.length;
if(target < nums[start] || target > nums[end]){
//因为升序,target只要超过两个边界即是不存在
return -1
}
else{
//执行二分查找函数
return research(start, end-1, target, nums);
}
function research(l, r, target, nums){
//m为l和r的中点,为向下取整,因为向右移会减一
var m = (l + r) >> 1;
//中点和终点重合结束循环,判断此时中/终点的值是否为target
while(m < r){
if(target == nums[m]){
return m;
}
if(target > nums[m]){
l = m + 1;
}else if(target < nums[m]){
r = m;
}
m =(l + r) >> 1;
}
return nums[m] == target ? l : -1;
}
};
递归【参考百科】:
var search = function(nums, target) {
var start = 0;
var end = nums.length;
return binary(start, end-1, target, nums);
function binary(l, r, target, nums) {
if (l <= r) {
if (nums[l] == target) {
return l;
}
if (nums[r] == target) {
return r;
}
var m = (l + r) >> 1;
if (nums[m] == target) {
return m;
} else if (nums[m] > target) {
return binary(l, m-1, target, nums);
} else {
return binary(m+1, r, target, nums);
}
}
return -1;
}
};
2.在排序数组中查找元素的第一个和最后一个位置
leetCode.34题(在排序数组中查找元素的第一个和最后一个位置)
利用二分查找,若找到目标值则继续向前/后遍历是否还存在目标值。
var searchRange = function(nums, target) {
let low =0
let high = nums.length-1;
let list = []
while(low<high){
let mid = (low + high) >> 1;
if(nums[mid]>target){
high = mid-1
}else if(nums[mid]<target){
low = mid+1
}else{
list[0] = mid;
list[1] = mid;
while(nums[mid-1]==target){
list[0] = mid-1
mid--
}
mid = list[1]
while(nums[mid+1]==target){
list[1] = mid+1;
mid++
}
return list;
}
}
return (nums[low]==target?[low,low]:[-1,-1])
};
3.1095山脉数组查找目标值
【参考作者:oppeuro】
/*
第一次查 分3种情况:查到正中间,查到左边,查到右边
1. 查到正中间(最简单的)左边递增右边递减,做两次二分即可。
2. 查到左侧分情况 如果查的数小于当前值,(左侧 -> 当前做二分)-(当前值 -> 右侧 看成一个新的山脉数组)
3. 查到右侧分情况 如果查的数大于当前值,(左侧 -> 当前值 看成一个新山脉数组)- (当前值 -> 右侧做二分)
*/
var findInMountainArray = function(target, mountainArr, start = 0, end = mountainArr.length()) {
// 递归出口,只有两值的时候直接求解即可
if(start > end) return -1;
if(end - start == 2){
if(mountainArr.get(start) == target) return start;
if(mountainArr.get(end - 1) == target) return end - 1;
return -1;
}
// 查找数组的范围, 中间值的前一值,中间值,中间值的后一值;通过这个3值确定当前位置。
let l = start, r = end, m = (l + r) >> 1,
last = mountainArr.get(m - 1), now = mountainArr.get(m), next = mountainArr.get(m + 1);
// 正中间
if(last < now && next < now){
if(target > now) return -1;
if(target == now) return m;
let left = seachLowToHeight(l, m, target, mountainArr);
return left == -1 ? seachHeightToLow(m + 1, r, target, mountainArr) : left;
}
// 左边
if(last < now && now < next){
if(target == now) return m;
if(target < now){
let left = seachLowToHeight(l, m, target, mountainArr)
return left == -1 ? findInMountainArray(target, mountainArr, m + 1, r) : left;
}
if(target > now){
return findInMountainArray(target, mountainArr, m + 1, r);
}
}
// 右边
if(last > now && now > next){
let left = findInMountainArray(target, mountainArr, l, m);
if(target == now){
return left == -1 ? m : left;
}
if(target < now){
return left == -1 ? seachHeightToLow(m + 1, r, target, mountainArr) : left;
}
if(target > now){
return left == -1 ? seachHeightToLow(l, m, target, mountainArr) : left;
}
}
return -1;
};
// 两个二分辅助函数,一个是小到大二分,一个是大到小二分
function seachLowToHeight(l, r, target, mountainArr){
let m = (l + r) >> 1, val = mountainArr.get(m);
while(l < r){
if(val == target){
return m;
}
if(val < target){
l = m + 1;
}else if(val > target){
r = m;
}
m = (l + r) >> 1;
val = mountainArr.get(m);
}
return val == target ? l : -1;
}
function seachHeightToLow(l, r, target, mountainArr){
let m = (l + r) >> 1, val = mountainArr.get(m);
while(l < r){
if(val == target){
return m;
}
if(val < target){
r = m;
}else if(val > target){
l = m + 1;
}
m = (l + r) >> 1;
val = mountainArr.get(m);
}
return val == target ? l : -1;
}
以上是关于leetcode每日一题(2020-4-29):1095. 山脉数组中查找目标值的主要内容,如果未能解决你的问题,请参考以下文章