如何以错误的顺序检查括号的有效性

时间:2018-11-08 00:09:23

标签: ruby-on-rails ruby

我必须编写一个方法,该方法接受一个字符串,如果方括号不为空,括号和大括号正确关闭,则返回true;否则返回false。

这就是我所拥有的:

  def empty_brackets?(string)
    %w[ () [] {} ].none?(&string.method(:include?))
  end

  def valid_string?(string)
    match_count = 0

    string.each_char do |c|
      match_count += 1 if [ '[', '{', '(' ].include?(c)
      match_count -= 1 if [ ']', '}', ')' ].include?(c)
    end
    match_count == 0
  end

我认为我的valid_string?方法不太可靠,但最重要的是,它没有通过括号(例如)somebrackets()顺序错误的测试。您能建议如何解决吗?

3 个答案:

答案 0 :(得分:3)

我的尝试,将所有左括号放入一个数组中,如果匹配则弹出右括号:

year    month   day     Total
2017    7       24      476.00
2017    7       26      1992.20
2017    7       30      877.50
2017    7               3345.70
2017    8       2       2362.40
2017    8               2362.40
2017                    5708.10
                        5708.10

答案 1 :(得分:1)

这是一个非常有效的版本。它使用正则表达式,并将所有的花括号({}[]())拉成一个小的数组,然后不断摆动对直到没有剩余。第二个它找到一个不匹配的对,它退出并返回false。它也不会将字符串拆分为char数组,因为它将使用两倍的内存(一次用于整个字符串,再一次用于将字符串拆分为单个字符)。

BRACKET_PAIRS = { '{' => '}', '[' => ']', '(' => ')' }
BRACKET_REGEX = /#{BRACKET_PAIRS.to_a.flatten.map { |v| Regexp.escape(v) }.join('|')}/

def valid?(string)
  brackets = string.scan(BRACKET_REGEX)
  while brackets.size > 0
    first = brackets.shift
    last = brackets.pop
    return(false) unless BRACKET_PAIRS[first] == last
  end

  return(true)
end

如果根本没有括号,此代码将返回true。

如果您不喜欢这样做,请执行以下操作:

BRACKET_PAIRS = { '{' => '}', '[' => ']', '(' => ')' }
BRACKET_REGEX = /#{BRACKET_PAIRS.to_a.flatten.map { |v| Regexp.escape(v) }.join('|')}/

def valid?(string)
  brackets = string.scan(BRACKET_REGEX)
  return(false) unless brackets.size > 0 # this line is added

  while brackets.size > 0
    first = brackets.shift
    last = brackets.pop
    return(false) unless BRACKET_PAIRS[first] == last
  end

  return(true)
end

作为旁注,您将希望避免像在示例中那样在循环中创建数组:

string.each_char do |c|
  match_count += 1 if [ '[', '{', '(' ].include?(c)
  match_count -= 1 if [ ']', '}', ')' ].include?(c)
end

此代码将在您的string变量中创建两个数组和每个字符6个字符串。这是非常低效的,您将使用比必要数量更多的RAM和CPU。您至少要使这两个数组在循环外,因为它们不会改变,并且理想情况下甚至使它们成为常数,这样您甚至在每次调用该方法时都不会使其成为数组。在您的程序启动时将其设置为一个,并永久使用它。像这样的小事情实际上会产生很大的不同,尤其是在循环中使用时。

答案 2 :(得分:1)

CLOSE_TO_OPEN = { ']'=>'[', '}'=>'{', ')'=>'(' }

def valid?(str)
  str.each_char.with_object([]) do |c,stack|
    case c
    when '[', '{', '('
      stack << c
    when ']', '}', ')'
      return false unless stack.pop == CLOSE_TO_OPEN[c]
    end
  end.empty?
end

valid? "[a]{b[c{d}e]fg}" #=> true
valid? "[a]{b[c{d]e}fg}" #=> false

可以通过添加一些puts语句来看到方法的行为。

def valid?(str)
  str.each_char.with_object([]) do |c,stack|
    puts "c=#{c}, stack=#{stack}"
    case c
    when '[', '{', '('
      stack << c
      puts "  stack after 'stack << #{c}' = #{stack}"
    when ']', '}', ')'
      print "  stack.pop (#{stack.last||'nil'})==CLOSE_TO_OPEN[#{c}] " +
            "(#{CLOSE_TO_OPEN[c]})=>"
      puts stack.last == CLOSE_TO_OPEN[c] ? "true, so continue" :
        "false, so return false"
      return false unless stack.pop == CLOSE_TO_OPEN[c]
    end
  end.tap { |stack| puts "At end, '#{stack}.empty?` (#{stack.empty?})" }.empty?
end

valid? "[a]{b[c{d}e]fg}"
c=[, stack=[]
  stack after 'stack << [' = ["["]
c=a, stack=["["]
c=], stack=["["]
  stack.pop ([)==CLOSE_TO_OPEN[]] ([)=>true, so continue
c={, stack=[]
  stack after 'stack << {' = ["{"]
c=b, stack=["{"]
c=[, stack=["{"]
  stack after 'stack << [' = ["{", "["]
c=c, stack=["{", "["]
c={, stack=["{", "["]
  stack after 'stack << {' = ["{", "[", "{"]
c=d, stack=["{", "[", "{"]
c=}, stack=["{", "[", "{"]
  stack.pop ({)==CLOSE_TO_OPEN[}] ({)=>true, so continue
c=e, stack=["{", "["]
c=], stack=["{", "["]
  stack.pop ([)==CLOSE_TO_OPEN[]] ([)=>true, so continue
c=f, stack=["{"]
c=g, stack=["{"]
c=}, stack=["{"]
  stack.pop ({)==CLOSE_TO_OPEN[}] ({)=>true, so continue
At end, '[].empty?` (true)
  #=> true

valid? "[a]{b[c{d]e}fg}"
c=[, stack=[]
  stack after 'stack << [' = ["["]
c=a, stack=["["]
c=], stack=["["]
  stack.pop ([)==CLOSE_TO_OPEN[]] ([)=>true, so continue
c={, stack=[]
  stack after 'stack << {' = ["{"]
c=b, stack=["{"]
c=[, stack=["{"]
  stack after 'stack << [' = ["{", "["]
c=c, stack=["{", "["]
c={, stack=["{", "["]
  stack after 'stack << {' = ["{", "[", "{"]
c=d, stack=["{", "[", "{"]
c=], stack=["{", "[", "{"]
  stack.pop ({)==CLOSE_TO_OPEN[]] ([)=>false, so return false
  #=> false