给定一个唯一正整数数组,为每个元素找到最近的较小元素,但距离至少为 k

Posted

技术标签:

【中文标题】给定一个唯一正整数数组,为每个元素找到最近的较小元素,但距离至少为 k【英文标题】:Given an array of unique positive integers, find the closest smaller element for each element, but at a distance of atleast k 【发布时间】:2016-10-09 01:13:51 【问题描述】:

我所指的问题类似于this one。唯一的区别是 1.) 从当前元素到我们选择的最近的较小元素应该有至少“k”个单位的距离。 2.) 可以从任一方向、向左或向右拾取元素。例如,如果 k=4 并且在当前元素旁边有一个较小的元素,我们不能选择它,因为它太靠近了。

我尝试以与其他解决方案相同的方式实现它。我所做的更改是,每次从堆栈中删除一个元素时,如果它实际上小于当前元素但仅仅因为它比 k 个单位更近而被删除,那么一旦我找到答案,我就会将该元素添加回堆栈当前元素,然后移动到下一个元素。这似乎可行,但我确信有更有效的方法来解决这个问题。任何建议都会非常有帮助。

【问题讨论】:

你的距离是标量还是方向?例如。在 [1, 0, 3, 1] 中距离为 1 的 3 的最近最小元素是前面的 0 还是后面的 1?距离-1呢? 解决链接的问题,然后在回答查询之前将k添加到每个查询的索引中。 @le_m 距离的方向无关紧要。它可以在左边或右边。在您的情况下,您可以选择 0 或 1。 @j_random_hacker 我认为这行不通。当您将 k 添加到查询中时,您会找到具有不同值的完全不同元素的答案。 @HarshaReaper "唯一的区别是......" - 显然有两个区别,1. 最小距离 k 和 2. 你想找到最近的更小的元素在两个方向上,与仅执行前向遍历的链接问题相反。正确的?如果是,请更新您的问题。 【参考方案1】:

运行时间和空间复杂度为 O(n) 的解决方案

仅前向遍历: 以下算法是对Given an array, find out the next smaller element for each element 答案的修改,并为输入数组的每个元素返回最近的较小后继元素,并保证元素与后继元素之间的最小距离:

// Traversal in forward direction only:
function smaller(array, distance) 
    var length = array.length,
        result = new Array(length).fill(null),
        stack = [];
    
    // Forward pass:
    for (var i = 0, j = distance; j < length; ++i, ++j) 
      while (stack.length > 0 && array[j] < array[stack[stack.length - 1]]) 
        result[stack.pop()] = array[j];
      
      stack.push(i);
    
    return result;


console.log(smaller([0, 2, 1], 0)); // [null, 1, null]
console.log(smaller([5, 2, 1, 7, 6, 0], 1)); // [1, 0, 0, 0, null, null]

前向和后向遍历:以下算法为输入数组的每个元素返回最近的较小后继或前驱,并保证元素与后继之间的最小距离或前任。

它的工作原理类似于第一个算法,但在两个方向上遍历数组并存储索引,而不是较小元素的值。在最后的第三遍中,从两遍的结果中选择最近的较小元素:

// Traversal in both directions:
function smaller(array, distance) 
    var length = array.length,
        forward = new Array(length).fill(null),
        backward = new Array(length).fill(null),
        stack = [];
  
    // Forward pass:
    for (var i = 0, j = distance; j < length; ++i, ++j) 
      while (stack.length > 0 && array[j] < array[stack[stack.length - 1]]) 
        forward[stack.pop()] = j;
      
      stack.push(i);
    

    // Backward pass:
    stack = [];
    for (var i = length - 1, j = length - distance - 1; j >= 0; --i, --j) 
      while (stack.length > 0 && array[j] < array[stack[stack.length - 1]]) 
        backward[stack.pop()] = j;
      
      stack.push(i);
    
    
    // Pick closest elements from both passes:
    for (var i = 0; i < length; ++i) 
      if (backward[i] !== null) 
        if (forward[i] !== null && forward[i] - i < i - backward[i]) 
          forward[i] = array[forward[i]];
         else 
          forward[i] = array[backward[i]];
        
       else if (forward[i] !== null) 
        forward[i] = array[forward[i]];
       
    
    return forward;


console.log(smaller([0, 2, 1], 0)); // [null, 0, 0]
console.log(smaller([5, 2, 1, 7, 6, 0], 1)); // [1, 0, 0, 2, 1, null]

【讨论】:

以上是关于给定一个唯一正整数数组,为每个元素找到最近的较小元素,但距离至少为 k的主要内容,如果未能解决你的问题,请参考以下文章

给定一个数组,找出每个元素的最后一个较小的元素

PTA——特殊堆栈

寻找最近的较小素数的快速算法

函数式编程:将列表划分为给定大小的较小列表的习语?

2021-07-16:三个无重叠子数组的最大和。给定数组 nums 由正整数组成,找到三个互不重叠的子数组的最大和。每个子数组的长度为k,我们要使这3*k个项的和最大化。返回每个区间起始索引的列表(索

从向量数组中查找给定向量中公共元素的数量