Я выполняю некоторые тесты скорости для следующей задачи:
Учитывая 2 строки, s1 и s2, которые содержат только строчные буквы, выводятся, если буквы s1 можно переставить так, чтобы s2 стала подстрокой s1.
Я получил 2 решения в рубине:
Версия 1:
def scramble(s1,s2)
if s1.length < s2.length
return false
end
a = Array.new(26) { 0 }
b = Array.new(26) { 0 }
t1 = Time.now
(0 ... s1.length).each do |x|
a[s1[x].ord - 97] += 1
end
(0 ... s2.length).each do |x|
b[s2[x].ord - 97] += 1
end
t2 = Time.now
(0 ... 26).each do |x|
if a[x] < b[x]
return false
end
end
puts t2 - t1
return true
end
Эта версия сохраняет количество символов в s1 и s2 в таблице прямой адресации и сравнивает количество каждого символа. Должно быть понятно, что этот код выполняет приблизительно 2 * (N + M) операций, где N - это длина s1, а M - это длина s2.
Версия 2:
def scramble(s1,s2)
t1 = Time.now
c = s2.chars
c.uniq!
t = c.all?{|x| s2.count(x)<=s1.count(x)}
t2 = Time.now
puts t2 - t1
return t
end
Эта версия также использует количество символов в s1 и s2, но не использует таблицу прямой адресации. Из того, что я понимаю, эта версия должна выполнять приблизительно 26 * (N + M) операций, поскольку сложность метода count () линейна по количеству символов в строке и вызывается для каждого отдельного символа в строке.
Когда я выполняю
scramble('abcdefghijklmnopqrstuvwxyz'*500000, 'abcdefghijklmnopqrstuvwxyz'*500000)
Первая версия занимает 4.424207s, а вторая - только 2.574269s. Я провел тест несколько раз с разными длинами s1 и s2, и результаты были согласованы (версия 2 намного быстрее, чем версия 1). Из-за их различных констант, я действительно запутался. Почему код в версии 2 работает намного быстрее, чем версия 1, несмотря на то, что его константа намного выше?
Может кто-нибудь, пожалуйста, посоветуйте мне?