2016-09-15 2 views
0

Для строки S длины N, которая индексируется от 0 до N-1, печатайте ее индексы с индексированием и нечетным индексом в виде строк, разделенных пробелами, на (см. пример ниже для более подробной информации). Пример ввода: выходКак не допускать ввода числа в переменную в Ruby

2 
Hacker 
Rank 

Пример:

Hce akr 
Rn ak 

объяснение:

S = "Hacker" S [0] = "Н", S [1] = "а ", S [2] =" c ", S [3] =" k ", S [4] =" e ", S [5] =" r "

Однако со следующим кодом I не смогли завершить ch allenge. Как принудительно вводить ввод как целое число?

S = gets.chomp.chars.to_a 


for i in 0..S.length 
    if i%2 == 0 
    s1 = S[i] 
    else 
    s2 = S[i] 
    end 
end 

puts s1.to_s + " " + s2.to_s 

ответ

0

Вот основной алгоритм, который бы O (N).

tests = gets.to_i 

# run the loop for number of tests given 
tests.times do 
    string = gets.chomp # sanitize string from input, i.e. removes \n \r 
    s_length = string.length # String length N 
    new_string = " " * s_length # create of string of length N 
    even_index = 0 # because evens are going to come first 
    odd_index = s_length - (s_length/2) + 1 # odds are going to start where even numbers end + 1 
    0.upto(s_length-1) do |i| 
    if i%2 == 0 
     new_string[even_index] = string[i] 
     even_index += 1 
    elsif 
     new_string[odd_index] = string[i] 
     odd_index += 1 
    end 
    end 
    puts new_string 
end 

Benchmark:

require 'benchmark' 

def using_ugly_algo(tests, string) 
    # tests = gets.to_i 

    tests.times do 
    string = string 
    s_length = string.length # String length N 
    new_string = " " * s_length # creat of string of length N 
    even_index = 0 
    odd_index = s_length - (s_length/2) + 1 
    0.upto(s_length-1) do |i| 
     if i%2 == 0 
     new_string[even_index] = string[i] 
     even_index += 1 
     elsif 
     new_string[odd_index] = string[i] 
     odd_index += 1 
     end 
    end 
    # new_string 
    end 
end 

def with_partition(amount, string) 
    amount.times do 
    input = string 
    (input.split('').partition.with_index do |_, i| 
     i.even? 
    end.map(&:join).join(' ')) 
    end 
end 


n = 10_000 
string = (0...500).map { ('a'..'z').to_a[rand(26)] }.join 

Benchmark.bmbm(100) do |x| 
    x.report("using_ugly_algo "){ n.times { using_ugly_algo(5, string) } } 
    x.report("with_partition "){ n.times { with_partition(5, string) } } 
end 

Доклад:

Rehearsal ---------------------------------------------------------------------------------------------------------------------------------------- 
using_ugly_algo                      13.790000 0.030000 13.820000 (13.843560) 
with_partition                      16.790000 0.030000 16.820000 (16.830992) 
------------------------------------------------------------------------------------------------------------------------------ total: 30.640000sec 

                              user  system  total  real 
using_ugly_algo                      13.930000 0.060000 13.990000 (14.070378) 
with_partition                      18.640000 0.210000 18.850000 (19.392816) 
+0

Кроме того, это абсолютно не идиоматический рубин, я считаю, что он потерпит неудачу в строках с нечетным количеством букв. Кроме того, когда вы говорите «O (n)», стоит упомянуть, что в этом конкретном случае «n». – mudasobwa

+0

@mudasobwa Это не подведет. Я тестировал его перед публикацией. Кроме того, если вы используете программное обеспечение, то все знают, что 'n' находится в o (n). Кроме того, только потому, что мы так привыкли к синтаксическому сахару рубина, давайте не будем забывать об основах. Если это делается с помощью 'map', затем' join', а затем другой операции, такой как раздел, тогда я теряю циклы. Подумайте о таких операциях на большой строке, скажем, 10^10, ваше решение займет много времени, чтобы рассчитать ответ. – Surya

+0

«скажем, 10^10», - набрал в консоли? Код должен решить проблему, а не пытаться быть швейцарским ножом. Использование сложных алгоритмов здесь является прекрасным примером преждевременной оптимизации, приводящей к нечитаемому и, как правило, плохому коду с запахом. – mudasobwa

1

Первый вход должен рассматриваться как целое (а именно, количество следующих строк, чтобы прийти):

amount = gets.to_i 

Теперь мы должны получить amount строк и делать свою работу (с помощью Enumerable#partition):

amount.times do 
    input = gets.chomp 
    puts (input.split('').partition.with_index do |_, i| 
    i.even? 
    end.map(&:join).join(' ')) 
end 
+0

Nice использование 'partition'. Я бы, вероятно, использовал две отдельные строки: 'odd, even = input.each_char.partition.with_index (1) {| _, i | i.odd? } 'и' puts '# {odd.join} # {even.join} "', но это только вопрос личных предпочтений. (Мне не нравится добавлять вызовы методов к 'end') – Stefan

0

Ну, проблема у вас есть, если я использую правильный термин, ошибка использования. Ваш код устанавливает значения s1 и s2 независимо от того, какая последняя отмеченная буква вместо конкатенации. Изменение вам код, я полагаю, что вы ищете что-то вроде этого:

S = gets.chomp.chars.to_a 
s1 = "" 
s2 = "" 

for i in 0...S.length 
    if i%2 == 0 
     s1.concat(S[i]) 
    else 
     s2.concat(S[i]) 
    end 
end 

puts s1.to_s + " " + s2.to_s 
+0

' 0..S.length' неверно, должен быть негласный диапазон с тремя точками: '0 ... S.length'. – mudasobwa

+0

Спасибо, я не мог вспомнить, что это было, поэтому я просто предположил, что он правильно понял эту часть. Хотя я понимаю, что теперь я ответил только на часть его вопроса, забыл исключить номера записей. – Marcus

2

Код

def doit(str) 
    str.each_char.each_slice(2).with_object(['','']) do |(c_even, c_odd), (s_even, s_odd)| 
    s_even << c_even 
    s_odd << c_odd unless c_odd.nil? 
    end.join(' ') 
end 

Примеры

doit "abracadabra" 
    #=> "arcdba baaar" 
doit "Jack be nimble, Jack be quick" 
    #=> "Jc enml,Jc eqik akb ibe akb uc" 

Объяснение

Для

str = "abracadabra" 

enum0 = str.each_char 
    #=> #<Enumerator: "abracadabra":each_char> 

Мы можем преобразовать нумератор enum0 в массив, чтобы увидеть, какие значения он будет генерировать:

enum0.to_a 
    #=> ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a"] 

enum1 = enum0.each_slice(2) 
    #=> #<Enumerator: #<Enumerator: "abracadabra":each_char>:each_slice(2)> 
enum1.to_a 
    #=> [["a", "b"], ["r", "a"], ["c", "a"], ["d", "a"], ["b", "r"], ["a"]] 

enum2 = enum1.with_object(['','']) 
    #=> #<Enumerator: #<Enumerator: #<Enumerator: "abracadabra":each_char>:each_slice(2)> 
    # :with_object(["", ""])> 
enum2.to_a 
    #=> [[["a", "b"], ["", ""]], [["r", "a"], ["", ""]], [["c", "a"], ["", ""]], 
    # [["d", "a"], ["", ""]], [["b", "r"], ["", ""]], [["a"], ["", ""]]] 

Если вы исследуете Возврат значения, полученные при построении enum1 и enum2, вы увидите, что их можно считать «составными» энтузиастами.

Первый элемент enum2 генерируется и передается в блок, присвоения значений четырех блоков переменных :

(c_even, c_odd), (s_even, s_odd) = enum2.next 
     #=> [["a", "b"], ["", ""]] 
c_even #=> "a" 
c_odd #=> "b" 
s_even #=> "" 
s_odd #=> "" 

Расчет блока теперь выполняется.

s_even << c_even 
    #=> "a" 
s_odd << c_odd unless c_odd.nil? 
    # s_odd << c_odd unless false 
    # s_odd << c_odd 
    #=> "b" 

Возвращение значения "a" и "b" являются новые значения s_even и s_odd соответственно.

Теперь следующий элемент enum_2 генерируется, передается в блок и расчеты блока выполняются:

(c_even, c_odd), (s_even, s_odd) = enum2.next 
    #=> [["r", "a"], ["a", "b"]] 
s_even << c_even 
    # "a" << "r" 
    #=> "ar" 
s_odd << c_odd unless c_odd.nil? 
    # s_odd << c_odd unless "a".nil?  
    # s_odd << c_odd 
    #=> "ba" 

Расчеты продолжают таким образом, пока последнее значение enum2 не генерируется: ["a"]. Это приводит к назначению nil на c_odd, поэтому вторая строка блока не выполняется . Наконец, массив из двух строк соединен с разделительным пространством.

Другой способ

def doit(str) 
    str.each_char.with_index.with_object(' ') { |(c,i),s| 
    s.insert(i.even? ? s.index(' ') : s.size, c) } 
end 

doit "abracadabra" 
    #=> "arcdba baaar" 

1 Следующее выражение использует параллельное назначение (иногда называемый множественного присваивания) и устранения неоднозначности (иногда упоминается как разложение) для присвоения значений переменные.

2 Вторые альтернативные варианты могут быть написаны s_odd << c_odd.to_s или s_odd << c_odd || ''.

1

Обратите внимание, что вместо проверки индекса каждого персонажа, вы также можете использовать scan:

'Hacker'.scan(/(.)(.?)/) #=> [["H", "a"], ["c", "k"], ["e", "r"]] 
     .transpose  #=> [["H", "c", "e"], ["a", "k", "r"]] 
     .map(&:join)  #=> ["Hce", "akr"] 
     .join(' ')  #=> "Hce akr" 

Или, используя временные переменные:

s1 = '' 
s2 = '' 
'Hacker'.scan(/(.)(.?)/) { |a, b| s1 << a ; s2 << b } 
puts "#{s1} #{s2}" 
+0

Ницца, Стефан. Сначала я попробовал нечто подобное, но не думал о '?' В '(.?)'. –

Смежные вопросы