如何优化代码删除不需要的字符

时间:2017-06-07 00:56:22

标签: ruby

此代码是针对用户计算机存在错误的问题而设计的,每次他/她点击退格按钮时,它都显示“''符号。创建的程序应该修复此问题并输出预期的字符串,考虑到'<'代表退格。输入字符串最长可达10 ^ 6个字符,并且只包含小写字母和''。

我的代码似乎正在正确执行但是,当我提交时,网站上说它超出了测试5/25的时间限制。给定的时间是1秒。此外,如果只有'<'符号它不应该产生输出。

例如,

"hellooo<< my name is matthe<<" 

会输出

"hello my name is matt"

"ssadfas<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" 

不输出任何内容,等等。

以下是代码:

input = gets.chomp
while input[/[[:lower:]]</]
    input.gsub!(/[[:lower:]]</, "")
end
input.gsub!(/</, "")
puts"#{input}"

在上面的代码中,如果有任何小写字母位于&#39;&lt;&#;前面的情况下,我会留在while循环中。在任何地方,小写字母后跟一个&#39;&lt;&#39;它什么都没有替换。退出while循环后,如果有任何&#39;&lt;&#39;留下的符号,它们什么都没有替换。然后显示最后一个字符串。

我创建了一个测试,我认为这是我的代码的最坏情况:

input = ("a" + "<" + "a")*10000000

#input = gets.chomp
while input[/[[:lower:]]</]
    input.gsub!(/[[:lower:]]</, "")
end
input.gsub!(/</, "")
puts"#{input}"

我让程序在创建字符串和执行while循环之间停止,然后完全运行它以便能够在需要超过一秒的时间内进行观察。它似乎花了不到1秒钟。

如何将其修改为更快或更好的方法呢?

2 个答案:

答案 0 :(得分:2)

def backspace(str)
  bs_count = 0
  str.reverse.each_char.with_object([]) do |s, arr|
    if s == '<'
      bs_count += 1
    else
      bs_count.zero? ? arr.unshift(s) : bs_count -= 1
    end
  end.join
end

backspace "Now is the<< tim<e fo<<<r every<<<one to chill ou<<<<t"
  #=> "Now is t tier evone to chilt"

答案 1 :(得分:2)

您的方法很好,但如果您调整正则表达式,性能会更好。

卡里,我希望你不介意我在基准测试中也采用你的优秀解决方案?

基于MRI ruby​​ 2.3.0p0(2015-12-25修订版53290)完成基准测试[x64-mingw32] 我在我的示例字符串上使用.dup以确保没有任何方法更改输入样本。

$ary = array (
              [0] => array(
                      Id => 5931,
                      value=> cas,
                     ),
              [1] => array(
                      Id => 5950,
                      value=> bsd,
                     ),
              [2] => array(
                      Id => 5951,
                      value=> Canvas,
                     ),
              [3] => array(
                      Id => 5952,
                      value=> Grey,
                     )
       );

给出

require 'benchmark' 
input = ""
10_000_000.times{input << ['a','<'].sample}

def original_method inp
  while inp[/[[:lower:]]</]
    inp.gsub!(/[[:lower:]]</, "")
  end
  inp.gsub(/</, "")
end

def better_method inp
  tuple = /[^<]</
  while inp[tuple]
    inp.gsub!(inp[tuple], "")
  end
  inp.gsub(/</, "")
end

def backspace str
  bs_count = 0
  str.reverse.each_char.with_object([]) do |s, arr|
    if s == '<'
      bs_count += 1
    else
      bs_count.zero? ? arr.unshift(s) : bs_count -= 1
    end
  end.join
end

puts original_method(input.dup).length
puts better_method(input.dup).length
puts backspace(input.dup).length

Benchmark.bm do |x| 
  x.report("original_method")  { original_method(input.dup) }
  x.report("backspace      ")  { backspace(input.dup) }
  x.report("better_method  ")  { better_method(input.dup) }
end