简体   繁体   中英

Better way to write “matching balanced parenthesis” program in Ruby

This method is supposed to take a string and detect if the brackets '(' '{' '[' in the string are closing properly with the corresponding (opposite) brackets.

First, is there a more elegant, compact way to write this bit without using all the "or"s (||):

            split_array.each do |i| 
              if (i == "{" || i == "(" || i == "[")
                  left.push(i)
                else (i == "}" || i == ")" || i == "]")
                  right.push(i)
                end
             end

My second question is, is this code terrible (see below)? It seems I should be able to write this in way fewer lines, but logically, I haven't come up with another solution (yet.) The code works for most tests, but it returns false for this test (see all driver tests at bottom): p valid_string?("[ ( text ) {} ]") == true

Any critique would be greatly appreciated! (also, if there is a better section to post this, please let me know) Thanks!

def valid_string?(string)

    opposites = { "[" => "]", "{" => "}", "(" => ")", "]" => "[", "}" => "{", ")" => "(" }

        left = Array.new
        right = Array.new
        return_val = true

        split_array = string.split(//)
        split_array.delete_if { |e| e.match(/\s/) }

          split_array.each do |i| 
          if (i == "{" || i == "(" || i == "[")
              left.push(i)
            else (i == "}" || i == ")" || i == "]")
              right.push(i)
            end
          end

        # p left
        # p right

        left.each_index do |i|
          if left[i] != opposites[right[i]]
              return_val = false
          end
        end  
        return_val
    end 

    p valid_string?("[ ] } ]") == false
    p valid_string?("[ ]") == true
    p valid_string?("[  ") == false                 
    p valid_string?("[ ( text ) {} ]") == true    
    p valid_string?("[ ( text { ) } ]") == false  
    p valid_string?("[ (] {}") == false 
    p valid_string?("[ ( ) ") == false

------- Updated: After trying some different approaches, my refactor is this: -----------

def valid_string?(str)

    mirrored = { "[" => "]", "{" => "}", "(" => ")" }
    open_brackets = Array.new

    split_str_array = str.split("")

    split_str_array.each do |bracket| 
      if bracket.match(/[\[|\{|\(]/) then open_brackets.push(bracket)
      elsif bracket.match(/[\]|\}|\)]/)
        return false if mirrored[open_brackets.pop] != bracket
      end
    end
    open_brackets.empty?
end 

My approach is as below :

def valid_string?(string)
  open_paren = ['[','{','(']
  close_paren = [']','}',')']
  open_close_hash = {"]"=>"[", "}"=>"{", ")"=>"("}
  stack = []
  regex = Regexp.union(close_paren+open_paren)
  string.scan(regex).each do |char|
    if open_paren.include? char
      stack.push(char)
    elsif close_paren.include? char
      pop_val = stack.pop
      return false if pop_val != open_close_hash[char]
    end
  end
  open_paren.none? { |paren| stack.include? paren }
end 

valid_string?("[ ] } ]") # => false
valid_string?("[ ]") # => true
valid_string?("[  ") # => false
valid_string?("[ (] {}") # => false
valid_string?("[ ( ) ") # => false
valid_string?("[ ( text { ) } ]") # => false
valid_string?("[ ( text ) {} ]") # => true

Algorithm :

  1. Declare a character stack S .
  2. Now traverse the expression string exp.
    • If the current character is a starting bracket ( '(' or '{' or '[' ) then push it to stack.
    • If the current character is a closing bracket ( ')' or '}' or ']' ) then pop from stack and if the popped character is the matching starting bracket then fine else parenthesis are not balanced.
  3. After complete traversal, if there is some starting bracket left in stack then “not balanced”

The shortest regex solution is probably:

def valid_string? orig
  str = orig.dup
  re = /\([^\[\](){}]*\)|\[[^\[\](){}]*\]|\{[^\[\](){}]*\}/
  str[re] = '' while str[re]
  !str[/[\[\](){}]/]
end

How about:

class Brackets
  def self.paired?(s)
    stack = []
    brackets = { '{' => '}', '[' => ']', '(' => ')' }

    s.each_char do |char|
      if brackets.key?(char)
        stack.push(char)
      elsif brackets.values.include?(char)
        return false if brackets.key(char) != stack.pop
      end
    end
    stack.empty?
  end
end


Brackets.paired?("[ ] } ]") # => false
Brackets.paired?("[ ]") # => true
Brackets.paired?("[  ") # => false
Brackets.paired?("[ (] {}") # => false
Brackets.paired?("[ ( ) ") # => false
Brackets.paired?("[ ( text { ) } ]") # => false
Brackets.paired?("[ ( text ) {} ]") # => true

This should provide the same functionality

def valid_string?(string)
  #assume validity
  @valid = true
  #empty array will be populated inside the loop
  @open_characters = []
  #set up a hash to translate the open character to a closing character
  translate_open_closed = {"{" => "}","["=>"]","("=>")"}
  #create an array from the string loop through each item 
  string.split('').each do |e| 
    #adding it to the open_characters array if it is an opening character
    @open_characters << e if e=~ /[\[\{\(]/
    #if it is a closing character then translate the last open_character to 
    #a closing character and compare them to make sure characters are closed in order
    #the result of this comparison is applied to the valid variable
    @valid &= e ==  translate_open_closed[@open_characters.pop] if e=~ /[\]\}\)]/
  end
  #return validity and make sure all open characters have been matched
  @valid &= @open_characters.empty?
end

You could also do this with inject but it would be a bit less transparent.

Another way:

s = str.gsub(/[^\{\}\[\]\(\)]/, '')
while s.gsub!(/\{\}|\[\]|\(\)/, ''); end
s.empty?

Ex 1
str = "(a ()bb [cc{cb (vv) x} c ]ss) "
s = str.gsub(/[^\{\}\[\]\(\)]/, '') #=> "(()[{()}])"
while s.gsub!(/\{\}|\[\]|\(\)/, '') do; end
  s => "([{}])" => "([])" => "()" => "" gsub!() => nil
s.empty? #=> true

Ex 2
str = "(a ()bb [cc{cb (vv) x] c }ss) "
s = str.gsub(/[^\{\}\[\]\(\)]/, '')  #=> "(()[{()]})"
while s.gsub!(/\{\}|\[\]|\(\)/, '') do; end
  s => "([{]})" gsub!() => nil 
s.empty? #=> false

I was given this as part of a simulated interview coding challenge. In my case, there was also a parens map passed in { "(" => ")", "[" => "]" } , meaning types of parentheses could vary.

def balanced_parens(string, parens_map)
  # where we throw opening parens
  opening_parens = []
  i = 0
  while i < string.length
    # if current index is opening paren add to array
    if parens_map.keys.include? string[i]
      opening_parens << string[i]
    # if current index is closing paren, remove last item from opening_array 
    elsif parens_map.values.include? string[i]
      popped_paren = opening_parens.pop
      # checking that closing parens at current index is a match for last open parens in opening_array
      return false if string[i] != parens_map[popped_paren]
    end
    i += 1
  end
  # if opening_parens array is empty, all parens have been matched (&& value = true)
  opening_parens.empty?
end
def valid_string?(exp)
  return false if exp.size % 2 != 0
  curly = "{}"
  square = "[]"
  parenthesis = "()"
  emptystr = ""
  loop do 
   old_exp = exp
   exp = exp.sub(curly, emptystr)
   break if exp == emptystr
   exp = exp.sub(square, emptystr)
   break if exp == emptystr
   exp = exp.sub(parenthesis, emptystr)
   break if exp == emptystr || exp == old_exp
 end
 exp == emptystr
end

You can try this approach:

def balanced_brackets?(string)
  # your code here
  stack = []
  opening_bracket = ['{','[', '(']
  closing_bracket = ['}', ']', ')']
  string.chars.each do |char|
    if opening_bracket.include?(char)
      stack << char
    elsif closing_bracket.include?(char)
      value = stack.pop
      return false if opening_bracket.index(value) != closing_bracket.index(char)
    end
  end
  
  stack.empty?
end

if you want to understand pseudo code try this link from coursera (starts at 0:56).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM