如何返回数组中的第三个最大数字

时间:2017-01-26 17:13:06

标签: arrays ruby while-loop

我回答编程问题的代码逻辑是:

  1. 找到输入数组中的最大数字。
  2. 将该号码存储在新阵列中。
  3. 从输入数组中删除该数字。
  4. 重复#1-3,直到我在新数组中有三个元素。
  5. 选择要返回的数组的最后一个元素。
  6. 我的代码返回三个10,而不是数组中的三个最大元素,10,8和4.我认为这可能是因为一旦内部while循环完成,代码就无法返回到它?

    我的测试代码是:

    puts(third_greatest([8, 1, 10, 4])).to_s
    

    我的代码是:

    def third_greatest(nums)
      greatest_number = nil
      three_greatest = []
    
      three_greatest_idx = 0
    
      while three_greatest_idx < 3
        number_idx = 0
    
        while number_idx < nums.length
          current_number = nums[number_idx]
    
          if greatest_number == nil
            greatest_number = current_number
          elsif greatest_number < current_number
            greatest_number = current_number
          end
    
          number_idx += 1
        end
    
        three_greatest.unshift(greatest_number)
        nums.delete(greatest_number)
        three_greatest_idx += 1
      end
    
      return three_greatest
    end
    

5 个答案:

答案 0 :(得分:12)

一旦你开始考虑解决像这样的问题,Ruby方式,我的意思是更多地依靠Enumerable并表达你的意图作为一系列简单的操作,经常链接在一起,然后解决方案变得更容易找到。

例如,要找到任意数组中的三个最高数字,显而易见的解决方案可能是:

def three_greatest(list)
  list.sort.reverse.first(3)
end

对列表进行排序,默认情况下从最低到最高,然后将其反转,使其从最高到最低。最后一个操作是复制前三个entires。这看起来非常合理,因为它非常清楚地表达了您的意图并且运作良好。

问题是,如果你仔细观察可枚举的产品,那么使用max会有更简单的解决方案:

def three_greatest(list)
  list.max(3)
end

这里要学到的教训是,Enumerable库与机械师的工具箱不同,它拥有大量有用的工具。重要的是要花一些时间来至少阅读那里的内容,这样你就不会浪费时间重新发明已经存在的优雅形式的东西。

换句话说,在解决问题时,请检查问题是否已经解决。在许多情况下,您会发现有一种工具可以完全满足您的需求。

答案 1 :(得分:6)

只是为了帮助人们了解maxsort与不使用内置方法之间的效果差异:

require 'fruity'

ary = (1..100).to_a.shuffle

def use_max(a)
  a.max(3).last
end

def use_sort(a)
  a.sort[-3]
end

def nth_greatest(nums, n)
  nums = nums.dup # prevent mutating the original array
  result = nil
  n.times do
    idx, max = -1, -Float::INFINITY
    nums.length.times do |i|
      idx, max = [i - 1, nums[i - 1]] if nums[i - 1] > max
    end
    result = nums.delete_at idx
  end
  result
end

compare do
  sorted { use_sort(ary) }
  maxed  { use_max(ary) }
  nth_greatested { nth_greatest(ary, 3) }
end

# >> Running each test 512 times. Test will take about 1 second.
# >> sorted is faster than maxed by 2x ± 0.1
# >> maxed is faster than nth_greatested by 3x ± 0.1

增加数组的大小:

ary = (1..1_000).to_a.shuffle

结果:

# >> Running each test 64 times. Test will take about 1 second.
# >> maxed is faster than sorted by 80.0% ± 10.0%
# >> sorted is faster than nth_greatested by 3x ± 0.1

再次提升数组大小:

ary = (1..10_000).to_a.shuffle

结果:

# >> Running each test 8 times. Test will take about 1 second.
# >> maxed is faster than sorted by 3x ± 0.1
# >> sorted is faster than nth_greatested by 2x ± 0.1
  

文档没有提到max(3)是否返回反向排序的数组,即使它看起来像。

文档示例是:

a.max(2) #=> ["horse", "dog"]

正在下降,但这不是一个很好的例子,因为使用数字更容易看到:

ary.max(3) # => [100, 99, 98]

以下是使用Benchmark显示基线速度的一些结果:

require 'benchmark'

ary = (1..5).to_a.shuffle

10.times do
  Benchmark.bm(4) do |b|
    b.report('sort') { ary.sort[-3] }
    b.report('max') { ary.max(3).last }
  end
end

# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000010)
# >> max    0.000000   0.000000   0.000000 (  0.000006)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000003)
# >> max    0.000000   0.000000   0.000000 (  0.000004)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000003)
# >> max    0.000000   0.000000   0.000000 (  0.000004)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000003)
# >> max    0.000000   0.000000   0.000000 (  0.000003)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000003)
# >> max    0.000000   0.000000   0.000000 (  0.000004)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000003)
# >> max    0.000000   0.000000   0.000000 (  0.000004)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000005)
# >> max    0.000000   0.000000   0.000000 (  0.000005)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000003)
# >> max    0.000000   0.000000   0.000000 (  0.000004)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000003)
# >> max    0.000000   0.000000   0.000000 (  0.000003)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000003)
# >> max    0.000000   0.000000   0.000000 (  0.000003)

增加数组的大小:

ary = (1..100).to_a.shuffle

# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000020)
# >> max    0.000000   0.000000   0.000000 (  0.000013)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000013)
# >> max    0.000000   0.000000   0.000000 (  0.000011)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000010)
# >> max    0.000000   0.000000   0.000000 (  0.000010)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000009)
# >> max    0.000000   0.000000   0.000000 (  0.000010)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000009)
# >> max    0.000000   0.000000   0.000000 (  0.000010)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000008)
# >> max    0.000000   0.000000   0.000000 (  0.000010)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000008)
# >> max    0.000000   0.000000   0.000000 (  0.000010)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000008)
# >> max    0.000000   0.000000   0.000000 (  0.000013)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000011)
# >> max    0.000000   0.000000   0.000000 (  0.000010)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000008)
# >> max    0.000000   0.000000   0.000000 (  0.000010)

并且:

ary = (1..1_000).to_a.shuffle

# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000110)
# >> max    0.000000   0.000000   0.000000 (  0.000057)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000103)
# >> max    0.000000   0.000000   0.000000 (  0.000054)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000101)
# >> max    0.000000   0.000000   0.000000 (  0.000053)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000100)
# >> max    0.000000   0.000000   0.000000 (  0.000053)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000100)
# >> max    0.000000   0.000000   0.000000 (  0.000053)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000100)
# >> max    0.000000   0.000000   0.000000 (  0.000056)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000099)
# >> max    0.000000   0.000000   0.000000 (  0.000053)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000099)
# >> max    0.000000   0.000000   0.000000 (  0.000053)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000100)
# >> max    0.000000   0.000000   0.000000 (  0.000053)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000099)
# >> max    0.000000   0.000000   0.000000 (  0.000053)

答案 2 :(得分:3)

您忘了取消greatest_number

  nums.delete(greatest_number)
  three_greatest_idx += 1
  greatest_number = nil # this line
end

显然在Ruby中有一个非常简单的解决方案,但我理所当然地认为你想自己做。

答案 3 :(得分:2)

我认为这是一项不允许大量使用Enumerable模块的任务。还有更简单的方法。例如。你不需要维护另一个数组:只需从原始数组中删除最高N次:

def nth_greatest(nums, n)
  nums = nums.dup # prevent mutating the original array
  result = nil
  n.times do
    idx, max = -1, -Float::INFINITY
    nums.length.times do |i|
      idx, max = [i - 1, nums[i - 1]] if nums[i - 1] > max
    end
    result = nums.delete_at idx
  end
  result
end

nth_greatest [8, 1, 10, 4], 2
#⇒ 8
nth_greatest [8, 1, 10, 4], 3
#⇒ 4

答案 4 :(得分:1)

对它进行排序并使用Ruby的负数索引选项。

[8, 1, 10, 4].sort[-3]
>> 4

编辑:经过多次测试后,我确定上面显示的排序方法比下面的方法更快,如果在搜索m个元素数组中的第n个最大数字时,n> 1/20的大小m。因为在你的例子中我们正在寻找4个元素数组中的第3个最大数字,而3个比.2大得多,所以上面的答案明显比这个替代方法更有效:

[8, 1, 10, 4].max(3)[-1]
>> 4