【力扣leetcode】队列中可以看到的人数

82 阅读2分钟

题目

有 n 个人排成一个队列,从左到右 编号为 0 到 n - 1 。给你以一个整数数组 heights ,每个整数 互不相同heights[i] 表示第 i 个人的高度。

一个人能 看到 他右边另一个人的条件是这两人之间的所有人都比他们两人  。更正式的,第 i 个人能看到第 j 个人的条件是 i < j 且 min(heights[i], heights[j]) > max(heights[i+1], heights[i+2], ..., heights[j-1]) 。

请你返回一个长度为 n 的数组 **answer **,其中 **answer[i] **是第 i 个人在他右侧队列中能 看到 的 人数 。

解题方式一

/**
 * @param {number[]} heights
 * @return {number[]}
 */

var canSeePersonsCount = function (heights) {
    let target = [];
    heights.map((item, index, arr) => {
        const other = arr.slice(index + 1);
        let i = 0;
        other.map((piece, pIndex, pArr) => {
            const pIndex1 = arr.findIndex(j => j == piece)
            const middle = arr.slice(index + 1, pIndex1);
            if (Math.min(item, piece) > Math.max.apply(null, middle)) {
                i++;
            }
        });
        target.push(i)
    });
    return target
};

将目标数组heights遍历,每一项为item,截取出每一项后面的数组项,组成新数组other, 遍历other,每一项为piece, 找到item和piece中间项组成的数组middle,然后Math.min(item, piece) > Math.max.apply(null, middle),则 item可以看到piece,i++

这种解法,在数组长度很大时,很消耗性能

image.png

更好的解法

/**
 * @param {number[]} heights
 * @return {number[]}
 */
var canSeePersonsCount = function (heights) {
  const n = heights.length;
  const res = new Array(n).fill(0);
  // 保证栈中为递增
  const stack = [];
  // 放最后项的索引
  stack.unshift(n - 1);
  // 从右向左遍历
  for (let i = n - 2; i >= 0; i--) {
    // 栈顶元素比当前元素矮
    while (stack.length && heights[i] > heights[stack[0]]) {
      // 从头部移出下标,后续左侧的人看不到此编号
      stack.shift();
      // 可见人数增加
      res[i]++;
    }
    // 栈中还有元素,那么栈顶元素比当前人员高,到此终止,后续人员看不到
    if (stack.length > 0) {
      res[i]++;
    }
    // 在头部加入下标
    stack.unshift(i);
  }
  return res;
};

上面的写法性能更好,在大数组的情况下,执行的速度很快。