LeetCode - 852 - 山脉数组的峰顶索引(peak-index-in-a-mountain-array)

一 目录

不折腾的前端,和咸鱼有什么区别

目录
一 目录
二 前言
三 解题及测试
四 LeetCode Submit
五 解题思路
六 进一步思考

二 前言

  • 难度:简单

  • 涉及知识:二分查找

  • 题目地址

  • 题目内容

我们把符合下列属性的数组 A 称作山脉:

* A.length >= 3
* 存在 0 < i < A.length - 1,
使得A[0] < A[1] < ... A[i-1] < A[i]
> A[i+1] > ... > A[A.length - 1]

给定一个确定为山脉的数组,
返回任何满足:
A[0] < A[1] < ... A[i-1] < A[i]
> A[i+1] > ... > A[A.length - 1]
的 i 的值。

示例 1:

输入:[0,1,0]
输出:1

示例 2:

输入:[0,2,1,0]
输出:1

提示:

3 <= A.length <= 10000
0 <= A[i] <= 10^6
A 是如上定义的山脉

三 解题及测试

小伙伴可以先自己在本地尝试解题,再回来看看 jsliang 的解题思路。

  • LeetCode 给定函数体

/**
 * @param {number[]} A
 * @return {number}
 */
var peakIndexInMountainArray = function(A) {
    
};

根据上面的已知函数,尝试破解本题吧~

确定了自己的答案再看下面代码哈~

index.js

/**
 * @name 山脉数组的峰顶索引
 * @param {number[]} A
 * @return {number}
 */
const peakIndexInMountainArray = (A) => {
  return A.indexOf(Math.max(...A));
};

console.log(peakIndexInMountainArray([0, 1, 0])); // 1
console.log(peakIndexInMountainArray([0, 1, 2, 0])); // 2

node index.js 返回:

1
2

四 LeetCode Submit

Accepted
* 32/32 cases passed (52 ms)
* Your runtime beats 97.87 % of javascript submissions
* Your memory usage beats 45 % of javascript submissions (34.9 MB)

五 解题思路

拿到题目,细细思考一下,抖了下机灵:

一行求解

const peakIndexInMountainArray = (A) => A.indexOf(Math.max(...A));

一行求解!

Math.max 可以塞多个元素,所以我们通过 ...A 进行数组解耦,传入 Math.max 中。

然后通过 indexOf 查找到位置即可~

Submit 提交如下:

Accepted
* 32/32 cases passed (52 ms)
* Your runtime beats 97.87 % of javascript submissions
* Your memory usage beats 45 % of javascript submissions (34.9 MB)

然而,你并不知道的是,当中还有一些曲折:

两种方法

// findIndex
const peakIndexInMountainArray = (A) => A.findIndex(i => i === Math.max(...A));

// indexOf
const peakIndexInMountainArray = (A) => A.indexOf(Math.max(...A));

结果你知道会发生什么吗?

两种结局

// findIndex
Accepted
* 32/32 cases passed (440 ms)
* Your runtime beats 5.85 % of javascript submissions
* Your memory usage beats 14 % of javascript submissions (35.4 MB)

// indexOf
Accepted
* 32/32 cases passed (52 ms)
* Your runtime beats 97.87 % of javascript submissions
* Your memory usage beats 45 % of javascript submissions (34.9 MB)

那么,就是看下为何 findIndexindexOf 差别那么大了:

  • Difference Between indexOf and findIndex function of array - Stack Overflow

  • findIndex - MDN

  • indexOf - MDN

在这些文章中提到:

  • indexOf 的第一个参数希望查找一个 value 值,可以用于原始类型的数组。

  • findIndex 的一个参数希望一个 callback 回调函数,可以用于复杂数据类型的数组或者查找条件比一个值要复杂的情况。

根据 ECMA-262 标准,它们的实现方式分别为:

findIndex 实现机制

// https://tc39.github.io/ecma262/#sec-array.prototype.findIndex
if (!Array.prototype.findIndex) {
  Object.defineProperty(Array.prototype, 'findIndex', {
    value: function(predicate) {
     // 1. Let O be ? ToObject(this value).
      if (this == null) {
        throw new TypeError('"this" is null or not defined');
      }

      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0;

      // 3. If IsCallable(predicate) is false, throw a TypeError exception.
      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }

      // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
      var thisArg = arguments[1];

      // 5. Let k be 0.
      var k = 0;

      // 6. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ! ToString(k).
        // b. Let kValue be ? Get(O, Pk).
        // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
        // d. If testResult is true, return k.
        var kValue = o[k];
        if (predicate.call(thisArg, kValue, k, o)) {
          return k;
        }
        // e. Increase k by 1.
        k++;
      }

      // 7. Return -1.
      return -1;
    }
  });
}

indexOf 实现机制

// Production steps of ECMA-262, Edition 5, 15.4.4.14
// Reference: http://es5.github.io/#x15.4.4.14
if (!Array.prototype.indexOf) {
  Array.prototype.indexOf = function(searchElement, fromIndex) {

    var k;

    // 1. Let O be the result of calling ToObject passing
    //    the this value as the argument.
    if (this == null) {
      throw new TypeError('"this" is null or not defined');
    }

    var O = Object(this);

    // 2. Let lenValue be the result of calling the Get
    //    internal method of O with the argument "length".
    // 3. Let len be ToUint32(lenValue).
    var len = O.length >>> 0;

    // 4. If len is 0, return -1.
    if (len === 0) {
      return -1;
    }

    // 5. If argument fromIndex was passed let n be
    //    ToInteger(fromIndex); else let n be 0.
    var n = +fromIndex || 0;

    if (Math.abs(n) === Infinity) {
      n = 0;
    }

    // 6. If n >= len, return -1.
    if (n >= len) {
      return -1;
    }

    // 7. If n >= 0, then Let k be n.
    // 8. Else, n<0, Let k be len - abs(n).
    //    If k is less than 0, then let k be 0.
    k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);

    // 9. Repeat, while k < len
    while (k < len) {
      // a. Let Pk be ToString(k).
      //   This is implicit for LHS operands of the in operator
      // b. Let kPresent be the result of calling the
      //    HasProperty internal method of O with argument Pk.
      //   This step can be combined with c
      // c. If kPresent is true, then
      //    i.  Let elementK be the result of calling the Get
      //        internal method of O with the argument ToString(k).
      //   ii.  Let same be the result of applying the
      //        Strict Equality Comparison Algorithm to
      //        searchElement and elementK.
      //  iii.  If same is true, return k.
      if (k in O && O[k] === searchElement) {
        return k;
      }
      k++;
    }
    return -1;
  };
}

如果你不想看源码,那么也可以看看实验:

运行时间对比

A = [1, 2, 3, 2, 1];

console.time('findIndex');
const findNumIndex = (A) => A.findIndex(i => i === Math.max(...A));
findNumIndex(A);
console.timeEnd('findIndex');

console.time('indexOf');
const indexOfNum = (A) => A.indexOf(Math.max(...A));
indexOfNum(A);
console.timeEnd('indexOf');

输出结果为:

findIndex: 0.267ms
indexOf: 0.083ms

排除了提交 LeetCode 的网络问题,我们可以得知查找单个元素的时候,indexOf() 的效率的确是远远大于 findIndex()

所以,以后小伙伴们使用查找元素的时候,可以根据对着两种方式的了解,进而提高自己代码的效能~


不折腾的前端,和咸鱼有什么区别!

jsliang 会每天更新一道 LeetCode 题解,从而帮助小伙伴们夯实原生 JS 基础,了解与学习算法与数据结构。

浪子神剑 会每天更新面试题,以面试题为驱动来带动大家学习,坚持每天学习与思考,每天进步一点!

扫描上方二维码,关注 jsliang 的公众号(左)和 浪子神剑 的公众号(右),让我们一起折腾!

jsliang 的文档库 由 梁峻荣 采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。
基于https://github.com/LiangJunrong/document-library上的作品创作。
本许可协议授权之外的使用权限可以从 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 处获得。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值