かずとよのアウトプット日記

開発エンジニアを目指しています。

leetcode : Valid_Parentheses

こんにちは、かずとよです。

今回もleetcode。

まずは問題文が以下。

 

Given a string s containing just the characters '('')''{''}''[' and ']', determine if the input string is valid.

An input string is valid if:

  1. Open brackets must be closed by the same type of brackets.
  2. Open brackets must be closed in the correct order.

 

Example 1:

Input: s = "()"
Output: true

Example 2:

Input: s = "()[]{}"
Output: true

Example 3:

Input: s = "(]"
Output: false

Example 4:

Input: s = "([)]"
Output: false

Example 5:

Input: s = "{[]}"
Output: true

 

Constraints:

  • 1 <= s.length <= 104
  • s consists of parentheses only '()[]{}'.

 

簡単に解読すると

【与えられる文字列は、"(", ")", "{", "}", "[", "]" これら3種類の括弧のみ。

正しく使えているか判別しよう。】

ということみたい。

例1)"(" は ")" で閉じるのは、もちろんOK。

例3)"(" を "]" で閉じるのはダメ。

例4)最初と閉じとがおかしい。

みたいな感じですね。

 

 

ぶっちゃけ今回の問題、昨日から始めたのに、解けなさすぎて頭痛がやばくなって寝ました。

で、一旦コードから離れて、リフレッシュして、再挑戦!

 

・・・それでも解けなくて、他の人のコード見ました。

理解するまで読み込んで、勉強しました。

やっと理解できて自分でコード書けたので、アウトプット!

 

まずは、僕が最初書いてた、ダメダメコード↓↓

 

def is_valid(s)
    x = s.match(/(\((\]|\}))|(\[(\)|\}))|(\{(\)|\]))/)
    y = s.match(/\(\)|\[\]|\{\}/)
    z = s.match(/\)\(|\]\[|\}\{/)
    start_c = s.count("([{")
    end_c = s.count(")]}")
    if s.length == 1
      return false
    elsif x.to_s.length >= 2
      return false
    elsif y == nil
      return false
    elsif z.to_s.length >= 2
      return false
    elsif start_c == end_c
      return true
    end
end

 

ここまで、10回以上トライアンドエラーを繰り返してます。

ひとつクリアできても、次に出てくるテスト内容で引っかかるから、elseif増やして・・・みたいな感じで。

 

この後も、複数回これを繰り返しました。ほんとキリがないし、どんどんと見るに耐えないコードになっていってしまったので、挫折。

 

他の方があげてるコードを見て勉強し、自分なりに解釈して書いたコードが以下。

 

def is_valid(s)
  stack = []
  s.each_char do |c|
           # 渡された文字列を一文字ずつ繰り返し
    case c
           # cを以下の条件で振り分け
    when "(", "{", "["
           # 開始の括弧なら
      stack << c
           # cを配列へ。
#---------------------------------------①
    when ")"
           # )なら
      if stack.pop != "("
           # popメソッドで配列の最後を消しつつ、その要素が(じゃなければ
        return false
      end
#---------------------------------------①
#---------------------------------------①と同じ
    when "}"
      if stack.pop != "{"
        return false
      end
#---------------------------------------①と同じ
#---------------------------------------①と同じ
    when "]"
      if stack.pop != "["
        return false
      end
#---------------------------------------①と同じ
    end
  end
  return stack.empty?
           # 配列は空?→空ならtrue、何かあればfalse(空ということは、開始の括弧と閉じ括弧が同数)
end

 

まっっっったく違います。笑

 

 

まずは、最初僕が書いてたコードについて。

僕は何故か、正規表現を使いこなせば、コードを短く済ませる事ができるんじゃないか?と考えてしまいました。(正規表現使いこなせるのカッコイイから憧れてます)

その変なこだわりのせいで、目を酷使して、結果、頭痛くなったんだと思います。笑

正直、他の方のコードを参考にする数回前の失敗時点で、無理じゃね?って思ってたので、その段階で諦めて一旦まっさらの状態からスタートするべきだったかもしれません。

 

で、別の方のコードを参考にしたコード。

まず、popというメソッド。このコードの存在を知れた事がかなり大きかったです。

配列の最後の要素を消しつつその消した要素を扱えるとは・・・

今までの僕だと、stack[-1]で扱って、その後にdelete_atで消すとかしか発想がなかったので。

ほんと、知識は力だと思いました。

 

*今回の学び:

  • 書いていったコードがダメかもしれないなって思ったら、一旦捨ててみたほうが良いかもしれない。自分の最初の発想に囚われない。
  • 理解するためなら、他の方のコードは見た方がいい
  • popメソッドは、配列の最後の要素を消す。その際、消した要素を返す。
  • each_charでは、文字列を一文字ずつ繰り返し処理。
  • caseは、オブジェクトを指定し、後に書くwhenの条件にヒットしていたら、次のwhenかendまでの処理を実行する。