zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    Java基础学习总结(33)——Java8 十大新特性详解
    Java基础学习总结(33)——Java8 十大新特性详解
    RabbitMQ学习总结(6)——消息的路由分发机制详解
    RabbitMQ学习总结(6)——消息的路由分发机制详解
    Stanford公开课《编译原理》学习笔记(1~4课)
    补习系列(21)-SpringBoot初始化之7招式
    使用modelarts部署bert命名实体识别模型
    全面认识 RUST -- 掌控未来的雷电
    补习系列(20)-大话 WebSocket 与 "尬聊"的实现
    【开发者portal在线开发插件系列二】多条上下行消息(messageId的使用)
  • 原文地址:https://www.cnblogs.com/autumn-starrysky/p/12805132.html
Copyright © 2011-2022 走看看