EurekaMoments

ロボットや自動車の自律移動に関する知識や技術、プログラミング、ソフトウェア開発について勉強したことをメモするブログ

Valid Parentheses問題とC++サンプルコード

背景

プログラミングテストの練習問題として、
ハッシュマップとスタックを利用した
Valid Parentheses問題を解いたので、
その解法をメモしておく。

目次

問題

下記のような3種類のカッコで構成された文字列が与えられるとする。

'(', ')', '[', ']', '{', '}'

その与えられた文字列に対して、下記の条件を満たせばValid、
そうでなければInvalidと判定するアルゴリズムを実装する。

  1. 左カッコが、同じ種類の右カッコによって閉じられる
  2. 各種左カッコが正しい順番で右カッコにより閉じられている

例えば、

文字列が"()"ならValid, "(]"ならInvalidと判定される。

解法

まずは、同種類のカッコのペアリングを定義するために、
ハッシュマップを利用する。

vivi.dyndns.org

ここでは、各種類の右カッコをキー、左カッコを値に割り当てる。

そして、与えられた文字列がValidか判定するためにスタックを
利用する。
bituse.info

これら2種類のデータ構造を利用したアルゴリズムは下記のようになる。

  1. スタックを初期化
  2. 文字列に含まれるカッコを左から順番に参照
  3. 2で参照したのが左カッコだったら、スタックに格納
  4. 2で参照したのが右カッコだったら、スタックの一番上にある要素を参照
  5. スタックの一番上の左カッコが同種類なら、popしてスタックから削除
  6. 5の時点でpopできないようなら、その文字列はInvalidと判定して終了
  7. 2~6を最後のカッコまで繰り返す
  8. 最後に、まだスタックに要素が残っているようなら、その文字列はInvalidと判定

f:id:sy4310:20220319221820p:plain

このアルゴリズムを実装したC++サンプルコードは下記のようになる。

#include <iostream>
#include <unordered_map>
#include <stack>

using namespace std;

class ValidParentheses {
  private:
    // hash table that takes care of the mappings
    unordered_map<char, char> mappings;
  public:
    // initialize hash map with mappings
    ValidParentheses() {
      this->mappings[')'] = '(';
      this->mappings['}'] = '{';
      this->mappings[']'] = '[';
    }

    void is_valid(string input) {
      // initialize a stack to be used in the algorithm
      stack<char> stack_char;

      for (int i = 0; i < input.length(); i++) {
        char c = input[i];

        // if the current character is a closing bracket
        if (this->mappings.find(c) != this->mappings.end()) {
          // get the top of element of the stack
          // if the stack is empty, set a dummy value of '#'
          char top_element;
          if (stack_char.empty()) {
            top_element = '#';
          }
          else {
            top_element = stack_char.top();
            stack_char.pop();
          }

          if (top_element != this->mappings[c]) {
            cout << input << " is invalid" << endl;
            return;
          }
        }
        else {
          // if it was an opening bracket, push to the stack
          stack_char.push(c);
        }
      }

      if (stack_char.empty()) cout << input << " is valid" << endl;
      else cout << input << " is invalid" << endl;
    }
};

int main(void) {
  ValidParentheses vp;

  // test case 1
  string input_1 = "()";
  vp.is_valid(input_1);

  // test case 2
  string input_2 = "()[]{}";
  vp.is_valid(input_2);

  // test case 3
  string input_3 = "(]";
  vp.is_valid(input_3);
  
  return 0;
}

このアルゴリズムの計算量は、与えられる文字列の文字数を
nとした場合にO(n)となる。また、スタックから1つの要素を
popする際の計算量はO(1)となる。