Одним из многих способов сделать это является следующее.
def min_nbr_swaps(str)
return -1 unless str.size.even?
half = str.size/2
str1 = str[0,half]
str2 = str[half,half]
h = str2.each_char.with_object(Hash.new(0)) { |c,h| h[c] += 1 }
str1.each_char.count do |c|
case h[c]
when 0
true
else
h[c] -= 1
false
end
end
end
min_nbr_swaps('aaabbb') #=> 3
min_nbr_swaps('ab') #=> 1
min_nbr_swaps('abc') #=> -1
min_nbr_swaps('mnop') #=> 2
min_nbr_swaps('xyyx') #=> 0
min_nbr_swaps('xaxbbbxx') #=> 1
Шаги следующие.
str = 'xaxbbbxx'
str.size.even?
#=> 8.even? => true, so do not return -1
half = str.size/2
#=> 4
str1 = str[0,half]
#=> "xaxb"
str2 = str[half,half]
#=> "bbxx"
h = str2.each_char.with_object(Hash.new(0)) { |c,h| h[c] += 1 }
Используется форма Ха sh :: new , которая принимает аргумент, называемый значением по умолчанию. Все это означает, что когда парсер Ruby расширяется h[c] += 1
до
h[c] = h[c] + 1
h[c]
справа, возвращается значение по умолчанию h
, 0, если h
не имеет ключ c
. Например, когда h
пусто,
h['x'] = h['x'] + 1 #=> 0 + 1 => 1
h['x'] = h['x'] + 1 #=> 1 + 1 => 2
h
не имеет ключа 'x'
в первом выражении, поэтому h[c]
справа возвращает значение по умолчанию, 0
тогда как h
имеет этот ключ во втором выражении, поэтому значение по умолчанию не применяется.
Продолжение,
enum = str1.each_char
#=> #<Enumerator: "xaxb":each_char>
Теперь мы используем метод Enumerable # count для определения количества символов в str1
, которые необходимо изменить.
enum.count do |c|
case h[c]
when 0
true
else
h[c] -= 1
false
end
end
#=> 4
Первый элемент, переданный в блок count
, - str1[0] #=> 'x'
.
c = 'x'
При h['x'] #=> 2
оператор case
выполняет
h['x'] -= 1
и возвращает false
, что означает, что x
изменять не нужно. Теперь h #=> {"b"=>2, "x"=>1}
Далее переменной блока присваивается значение str1[1] #=> 'a'
:
c = 'a'
Как h['a'] #=> 0
, оператор case
возвращает true
, что означает a
необходимо изменить. Здесь h[a]
возвращает значение по умолчанию , 0
, поскольку h
не имеет ключа a
. h
не изменяется.
Остальные вычисления аналогичны, все возвращают false
. count
возвращает 1
, поскольку блок возвращает true
только для 1
из 4
символов в str1
.