【问题标题】:Finding 4 highest values from an array从数组中找到 4 个最高值
【发布时间】:2011-05-15 12:45:27
【问题描述】:

我如何使用max()从数组中挑选出最高的 4 个值而不是 1 个?

【问题讨论】:

  • 你不能用maxmax() 返回参数值中数值最高的值。如果多个值可以被认为具有相同的大小,则将返回第一个列出的值。
  • 正如戈登所说,你不能那样做。但是,您可以很聪明,一旦找到最大值 - 从数组中删除它并再次运行 max() 重复该过程直到您满意为止。

标签: php arrays max


【解决方案1】:

您可以使用SplMaxHeap

function maxN(array $numbers, $n)
{
    $maxHeap = new SplMaxHeap;
    foreach($numbers as $number) {
        $maxHeap->insert($number);
    }
    return iterator_to_array(
        new LimitIterator($maxHeap, 0, $n)
    );
}

用法(demo):

print_r( maxN( array(7,54,2,4,26,7,82,4,34), 4 ) );

【讨论】:

  • +1 用于简单、干净地使用迭代器和 SPL 数据结构来解决问题!
【解决方案2】:

你可以试试这个:

$a = array(3,5,6,1,23,6,78,99);
asort($a);
var_dump(array_slice($a, -4));

HTH。

【讨论】:

  • 这种方法的唯一缺点:它的运行时间在O(n log n),而不是应该的O(n)
  • @phihag - 这很有趣 - O(n+4) 解决方案会是什么样子?
  • @Robin 抱歉,实际上不是O(n+4),而是O(4n)(或只是O(n))。我添加了一个学术答案,但 Emil 的更好。
  • Kemal,我们谈论的是运行时复杂性。如果你增加一个问题的规模,解决它的时间会增加多少?假设您有一个算法可以解决 O(n^2) 中的问题。这意味着如果将问题规模加倍,运行时间就会增加四倍。 O(n) 的算法会以与问题大小相同的速度增加,例如,将大小加倍将花费两倍的时间。如果问题很大,这可能很重要。
  • 在大学的所有计算机科学课程中很早就教授了计算运行时复杂度。如果你有兴趣,我建议你拿起一本关于算法的书(例如这本书:amazon.com/Introduction-Algorithms-Second-Thomas-Cormen/dp/…
【解决方案3】:

这将在 Θ(n) 时间内完成:

$a = $b = $c = $d = null;
foreach($array as $v) {
  if(!isset($a) || $v > $a) {
    $d = $c;
    $c = $b;
    $b = $a;
    $a = $v;
  }elseif(!isset($b) || $v > $b) {
    $d = $c;
    $c = $b;
    $b = $v;
  }elseif(!isset($c) || $v > $c) {
    $d = $c;
    $c = $v;
  }elseif(!isset($d) || $v > $d) {
    $d = $v;
  }
}

$result = array($a, $b, $c, $d);

【讨论】:

  • 这真的很有趣,我刚刚做了一个快速的基准测试 (gist.github.com/973159),这确实更快,尽管它似乎只有在元素数量巨大时才会更快在数组中。我猜asort 解决方案是用 PHP(在较低级别)实现的这一事实也有影响。
  • 罗宾,你可能是对的。渐近运行时对于小问题并不是特别重要。
  • @Robin 在我的机器上速度并不快。我已经多次尝试过您的基准测试,array_slice 变体在第一次运行后的每次后续运行后都优于此。另见codepad.viper-7.com/5yMTuu
  • @Gordon - 请注意,我的 Gist 代码(和您的 Viper 代码)中有一个错误,函数 'fixed 应该说 return array($a,$b,$c,$d); 而不是 return array_slice($array, -4);。这可能对结果有影响。此外,在我的测试中,fixed 函数在小于 100,000 个项目的数组上速度较慢。
  • @Robin 啊,我明白了。是的。请参阅固定版本:codepad.viper-7.com/XN1w8Z 和超过 100k 元素的版本:codepad.viper-7.com/hXeTxl。这再次告诉我们,基准测试在没有上下文的情况下完全没用:)
【解决方案4】:
function maxs($ar, $count=4) 
{
    $res = array();

    foreach ($ar as $v) 
    {
        for ($i = 0;$i < $count;$i++) 
        {
            if ($i >= count($res) || $v > $res[$i]) 
            {
                do 
                {
                    $tmp = $res[$i];
                    $res[$i] = $v;
                    $v = $tmp;
                    $i++;
                } 
                while ($i < $count);
                    break;
            }
        }
    }
    return $res;
}

【讨论】:

  • ... 除了 rsort 将在 O(n log n) 中运行,或者你有没有办法证明它在这种特殊情况下会表现得更好?
  • 哦,也许你是对的。 $res 将是一个小数组,所以 rsort 的 nlogn 可以被认为是一个常数(我猜)。
  • @Emil Vikström 没错,rsort 将在 O(4 log 4) 中运行。对于较大的 4 值,必须有一个超过 2 行的辅助插入函数。
  • @Emil Vikström 更新为Θ(4n) 中的解决方案,而不是O(4n log(4)),它概括了您的解决方案(但看起来更丑;))。
  • 不错。你的解决方案现在应该和我的一样好。但是我认为您应该在渐近运行时复杂性中删除4 - 无论如何您已经删除了所有其他常量,那么为什么还要保留其中一个呢? ;-)
【解决方案5】:

一个使用php预定义函数的简单方法。

<?php
  $arr = array(6, 8, 3, 2, 7, 9);

  rsort($arr);

  $first = array_shift($arr);
  $second = array_shift($arr);
  $third = array_shift($arr);

  echo $first; // print 9
  echo $second; // print 8
  echo $third; // print 7
?>

【讨论】:

    【解决方案6】:

    在存储自身的同时,您可以在插入新项目后立即维护另一个数组,如果要插入的项目更大,请检查内部数组中的最大值插入此项目。在项目弹出期间反之亦然。从内部维护的数组中,您可以获得尽可能多的最大数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-29
      • 2019-05-27
      • 1970-01-01
      • 1970-01-01
      • 2018-03-26
      • 1970-01-01
      • 2014-02-09
      • 1970-01-01
      相关资源
      最近更新 更多