两个idx的总和等于零。重复索引

时间:2018-01-12 13:21:33

标签: ruby rspec

我正在编写一个方法的代码,该方法返回在Zero中添加结果的索引对的总和。我已经想到了一切,但是,我遇到了一个我无法找到的错误并且让我疯狂! 传递array = [-1, 0, 2, -2, 1].two_sum(我的方法)时,返回值为[[0, 4], [1, 1], [2, 3]]而不是[[0, 4], [2, 3]](该方法在末尾对arr进行排序)。出于某种原因,我的方法是两次使用idx 1,尽管我认为我已在代码中指定我只想比较idxidx + 1

我的代码出了什么问题?

这是我到目前为止所做的:

class Array
  def two_sum
    final_arr = []
    self.each_with_index do |each, idx|
      self.each_index do |comp_idx|
        unless comp_idx + 1 == self.length || idx == comp_idx
          if (each + self[comp_idx + 1]) == 0
            final_arr << [idx, comp_idx + 1].sort
          end
        end
      end
    end
    final_arr.sort
  end
end

感谢您的帮助!

4 个答案:

答案 0 :(得分:2)

此代码非常难以理解/维护。无论如何,有两个问题:

  1. 您阻止对idx == comp_idx执行任何操作,然后比较idxcomp_idx + 1
  2. 你来回迭代它,因此重复项([2, 3][3, 2]会泄漏到结果中。
  3. 以下是更正后的版本:

    class Array
      def two_sum
        final_arr = []
        self.each_with_index do |each, idx|
          self.each_index do |comp_idx|
            #                                     ⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓
            unless comp_idx + 1 == self.length || idx == comp_idx + 1
              if (each + self[comp_idx + 1]) == 0
                final_arr << [idx, comp_idx + 1].sort
              end
            end
          end
        end
        #             ⇓⇓⇓⇓⇓
        final_arr.sort.uniq
      end
    end
    

    Bonus track:更多惯用的ruby版本。

    ▶ arr.each.with_index.with_object([]) do |(e1, idx1), result|
        result << 
          ([idx1].product(
             arr[idx1 + 1, arr.length]. # compare only not yet compared
             each.
             with_index(idx1 + 1).      # adjust index
             select { |e2, idx2| (e1 ^ -e2).zero? }
          ))
      end.flatten(1).map { |i1, (_, i2)| [i1, i2] }
      #⇒ [[0, 4], [2, 3]]
    

答案 1 :(得分:0)

如果您对简单和rubyist的内容感到满意,可以尝试

arr = [-1, 0, 2, -2, 1]
[*0...arr.size].combination(2).to_a.each_with_object([]) do |a, final_arr| 
  final_arr << a if arr[a[0]]+arr[a[1]] == 0
end
final_arr.sort

答案 2 :(得分:0)

由于您的代码问题已经确定,我只会建议一种不同的,更有效的方法来计算所需的索引对。

<强>代码

def two_sum(arr)
  hneg = Hash.new { |h,k| h[k] = [] }
  hpos = Hash.new { |h,k| h[k] = [] }
  azero = []
  arr.each_index do |i|
    n = arr[i]
    case n <=> 0
    when -1 then hneg[-n] << i
    when  1 then hpos[n] << i
    else         azero << i
    end
  end
  (hneg.keys & hpos.keys).each_with_object(azero.combination(2).to_a) { |k,a|
    hneg[k].product(hpos[k]) { |pair| a << pair } }
end

<强>实施例

two_sum [3, -1, 0, 1, 4, 0, -4, 0, 1]
  #=> [[2, 5], [2, 7], [5, 7], [1, 3], [1, 8], [6, 4]]
two_sum [3, -1, 0, 1, 4, 0, -4, 0, -2, -4, 5, 4]
  #=> [[2, 5], [2, 7], [5, 7], [1, 3], [6, 4], [6, 11], [9, 4], [9, 11]]

如果[i,j]是返回的数组的元素,则arr[i] == arr[j] == 0arr[i] < 0arr[j] == -arr[i]。如果希望用i < j写入对,只需写下以下内容即可。

arr = [3, -1, 0, 1, 4, 0, -4, 0, -2, -4, 5, 4]
two_sum(arr).map { |pair| pair.first > pair.last ? pair.reverse : pair }
  #=> [[2, 5], [2, 7], [5, 7], [1, 3], [4, 6], [6, 11], [4, 9], [9, 11]]

<强>解释

步骤如下。

arr = [3, -1, 0, 1, 4, 0, -4, 0, 1]
hneg = Hash.new { |h,k| h[k] = [] }
  #=> {}
hpos = Hash.new { |h,k| h[k] = [] }
  #=> {}
azero = []
arr.each_index do |i|
  n = arr[i]
  case n <=> 0
  when -1 then hneg[-n] << i
  when  1 then hpos[n]  << i
  else         azero    << i
  end
end
  #=> [3, -1, 0, 1, 4, 0, -4, 0, 1]

我们刚刚创建了以下哈希和数组。

hneg
  #=> {1=>[1], 4=>[6]}
hpos
  #=> {3=>[0], 1=>[3, 8], 4=>[4]}
azero
  #=> [2, 5, 7]

这告诉我们arr[1] #=> -1的{​​{1}},arr[6] #=> -4arr[0] #=> 3arr[3] == arr[8] #=> 1arr[4] #=> 4arr[i] #=> 0。接着,

i = 2, 5, 7

这表明common_keys = hneg.keys & hpos.keys #=> [1, 4] hneg的公共密钥是hpos。 (我们不必担心其他密钥。)

现在计算映射到[1, 4]的所有索引对。

[0, 0]

最后,我们按如下方式获得所需的索引对。

zero_matches = azero.combination(2).to_a
  #=> [[2, 5], [2, 7], [5, 7]]

请注意,当公共密钥为common_keys.each_with_object(zero_matches) { |k,a| hneg[k].product(hpos[k]) { |pair| a << pair } } #=> [[2, 5], [2, 7], [5, 7], [1, 3], [1, 8], [6, 4]] 时,

k => 1

如果有k = 1 hneg[k].product(hpos[k]) #=> [[1, 3], [1, 8]] hneg[1] #=> [1, 2],我们就会获得

hpos[1] #=> [3, 4]

查看带有默认块的类方法Hash::new的表单,Integer#<=>Array#each_indexArray#combinationArray#product以及Enumerable#each_with_object

答案 3 :(得分:-1)

这是使用组合和选择

的其他工作解决方案
class Array
  def two_sum
    c = (0 .. count-1).to_a.combination(2).to_a
    c.select do |i,j|
      self[i]+self[j] == 0
    end
  end
end

a = [-1, 0, 2, -2, 1]
a.two_sum