Сумма двух idx равна нулю. Повторный индекс
Я пишу код для метода, который возвращает сумму пары его индексов, которые добавили результат в ноль. Я все понял, но я столкнулся с ошибкой, которую не смог найти, и сводит меня с ума! При прохождении array = [-1, 0, 2, -2, 1].two_sum
(мой метод) возвращаемое значение [[0, 4], [1, 1], [2, 3]]
вместо [[0, 4], [2, 3]]
(метод сортирует arr в конце). По какой-то причине мой метод принимает idx 1
дважды, хотя, я думаю, я указал в своем коде, что я хочу только сравнить idx
а также idx + 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 ответа
Этот код очень трудно понять / поддерживать. Во всяком случае, есть две проблемы:
- Вы предотвращаете любые действия на
idx == comp_idx
, а потом сравниidx
а такжеcomp_idx + 1
- Вы повторяете это назад и вперед и, следовательно, дубликаты (
[2, 3]
а также[3, 2]
просочиться в результат.
Вот исправленная версия:
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
Бонус-трек: более идиоматическая рубиновая версия.
▶ 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]]
Если вы в порядке с чем-то простым и рубиновым, вы можете попробовать
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
Поскольку проблема с вашим кодом была идентифицирована, я предложу только другой, более эффективный способ вычисления желаемых пар индексов.
Код
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] == 0
или же arr[i] < 0
а также arr[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
, arr[6] #=> -4
, arr[0] #=> 3
, arr[3] == arr[8] #=> 1
, arr[4] #=> 4
а также arr[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]
мы бы получили
hneg[1].product(hpos[1])
#=> [[1, 3], [1, 4], [2, 3], [2, 4]
Смотрите форму метода класса Hash::new, который принимает блок по умолчанию, Integer # <=>;;, Array # each_index, Array # комбинация и Array#product и Enumerable # each_with_object.
Вот другое рабочее решение с использованием комбинации и выберите
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