将数字插入有序数组

时间:2015-12-06 05:06:53

标签: ruby

我有一个以升序或降序排序的数字数组,我想找到插入数字的索引,同时保留数组的顺序。如果数组为[1, 5, 7, 11, 51]且要插入的数字为9,我会期待3,因此我可以执行[1, 5, 7, 11, 51].insert(3, 9)。如果数组是[49, 32, 22, 11, 10, 8, 3, 2]且要插入的数字是9,我会期待5所以我可以[49, 32, 22, 11, 10, 8, 3, 2].insert(5, 9)

在保留数组排序的同时,找到在这两个数组中插入9的索引的最佳/最干净的方法是什么?

我写了这段有用的代码,但它并不是很漂亮:

array = [55, 33, 10, 7, 1]
num_to_insert = 9
index_to_insert = array[0..-2].each_with_index.map do |n, index|
  range = [n, array[index.next]].sort
  index.next if num_to_insert.between?(range[0], range[1])
end.compact.first
index_to_insert # => 3

3 个答案:

答案 0 :(得分:3)

这不是一个好方法,但可能更清晰,因为您可以在升序或降序数组上使用方法insert_sorted(number),而不必担心它将被放置的索引:

module SortedInsert
  def insert_index(number)
    self.each_with_index do |element, index|
      if element > number && ascending?
        return index
      end

      if element < number && descending?
        return index
      end
    end

    length
  end

  def insert_sorted(number)
    insert(insert_index(number), number)
  end

  def ascending?
    first <= last
  end

  def descending?
    !ascending?
  end
end

在数组上使用它,如下所示:

array = [2, 61, 12, 7, 98, 64]

ascending = array.sort
descending = array.sort.reverse

ascending.extend SortedInsert
descending.extend SortedInsert

number_to_insert = 3

puts "Descending: "

p number_to_insert
p descending
p descending.insert_sorted(number_to_insert)

puts "Ascending: "

p number_to_insert
p ascending
p ascending.insert_sorted(number_to_insert)

这将给出:

Descending:
3
[98, 64, 61, 12, 7, 2]
[98, 64, 61, 12, 7, 3, 2]
Ascending:
3
[2, 7, 12, 61, 64, 98]
[2, 3, 7, 12, 61, 64, 98]

备注

  1. 该模块定义了一些将仅添加到特定Array对象的方法。
  2. 新方法提供了一个排序数组(升序/降序)方法insert_sorted(number),可以在排序位置插入数字
  3. 如果需要插入位置,也有一种方法:insert_index(number),它将提供需要插入数字的索引,以便结果数组保持排序。
  4. 警告:模块假设正在扩展的数组按升序或降序排序。

答案 1 :(得分:3)

Wand Maker的回答并不坏,但它有两个问题:

  1. 它对整个数组进行排序以确定它是升序还是降序。当你所要做的就是找到一个不等于之前的元素来比较第一个和最后一个元素以确定这一点时,这很愚蠢。在最糟糕的情况下,而不是 O n O (1) O n log n )。

  2. 在使用Array#index时使用bsearch。我们可以进行二进制搜索,而不是遍历整个数组,因为它已经排序。在最坏的情况下,这是 O (log n ),而不是 O n )。< / p>

  3. 我发现把它分成两种方法更清楚,但你当然可以把它变成一种:

    def search_proc(ary, n)
      case ary.first <=> ary.last
        when  1 then ->(idx) { n > ary[idx] }
        when -1 then ->(idx) { n < ary[idx] }
        else raise "Array neither ascending nor descending"
      end
    end
    
    def find_insert_idx(ary, n)
      (0...ary.size).bsearch(&search_proc(ary, n))
    end
    
    p find_insert_idx([1, 5, 7, 11, 51], 9)
    #=> 3
    
    p find_insert_idx([49, 32, 22, 11, 10, 8, 3, 2], 9)
    #=> 5
    

    (我在这里使用Range#bsearchArray#bsearch的工作方式相同,但使用范围返回索引更方便,效率更高,否则我们必须{ {1}}或其他什么。)

答案 2 :(得分:2)

这是我能想到的最简单的方法。

def find_insert_idx(ary, n)
  is_asc = (ary.sort == ary)
  if (is_asc)
    return ary.index { |i| i > n }
  else 
    return ary.index { |i| i < n }
  end
end

p find_insert_idx([1,5,7,11,51], 9)
#=> 3
p find_insert_idx([49,32,22,11,10,8,3,2], 9)
#=> 5