C++で有効な括弧列を作るための最小削除アルゴリズム
文字列 s が、'('・')' および小文字の英字で構成されているとします。このとき、残った括弧列が「有効」になるように、括弧 '(' または ')' を任意の位置から最小限削除し、有効な文字列を1つ返すことを考えます。
括弧列が有効であるとは、次の条件を満たすことです。
空文字列である、または小文字のみを含む
AB(A と B を連結した形)と表せる。ただし A・B はそれぞれ有効な文字列
(A) と表せる。ただし A は有効な文字列
たとえば、入力が "a)b(c)d" の場合、出力は "ab(c)d" となります。
アルゴリズムの考え方
この問題はスタックを使うことで効率的に解けます。対応する開き括弧を持たない閉じ括弧、および閉じ括弧を持たない余分な開き括弧を検出してマークし、最後にそれらを取り除くという流れです。
解法の手順
- 整数型のスタック
stを定義する - i を 0 から s のサイズまでループする
- s[i] が
'('の場合:i を st にプッシュする - s[i] が
')'の場合:- スタックが空でなければポップする(対応する開き括弧が見つかった)
- 空の場合は s[i] =
'*'とマークする(削除対象)
- s[i] が
- st が空でない間、次を繰り返す(余った開き括弧の処理)
- s[スタックの先頭要素] =
'*'とマークする - スタックからポップする
- s[スタックの先頭要素] =
- ans を空文字列として初期化する
- i を 0 から s のサイズ − 1 までループし、s[i] が
'*'でなければ ans に追加する - ans を返す
以下の実装例を見ると、理解がより深まるでしょう。
実装例
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
string minRemoveToMakeValid(string s) {
stack <int> st;
for(int i = 0; i < s.size(); i++){
if(s[i] == '(')st.push(i);
else if(s[i] == ')'){
if(!st.empty())st.pop();
else s[i] = '*';
}
}
while(!st.empty()){
s[st.top()] = '*';
st.pop();
}
string ans = "";
for(int i = 0; i < s.size(); i++){
if(s[i] != '*')ans += s[i];
}
return ans;
}
};
main(){
Solution ob;
cout << (ob.minRemoveToMakeValid("a)b(c)d"));
}
入力
"a)b(c)d"
出力
ab(c)d
計算量
時間計算量は O(n)、空間計算量は O(n) です(n は文字列の長さ)。各文字を高々1回ずつ処理し、スタックには最大で n 個のインデックスが格納されるためです。
-
Pythonで有効な括弧列を作るために必要な最小限の括弧削除を求めるプログラム
文字列 s には、括弧「(」「)」と小文字の英字が含まれているとします。この文字列から、任意の位置にある括弧「(」または「)」を最小限だけ削除し、結果として得られる括弧列を有効な状態にします。そして最終的に、有効な文字列を1つ返す必要があります。 ここで、括弧列が「有効」とみなされるのは、以下の条件のいずれかを満たす場合です。 文字列が空であるか、小文字の英字のみを含む場合 文字列が AB(A と B を連結した形)と表せる場合。ただし A と B はどちらも有効な文字列 文字列が (A) の形式で表せる場合。ただし A は有効な文字列 たとえば、入力が s = m)n(o)p の場
-
Pythonで括弧列を有効にするための最小追加数を求める方法
問題の概要 ( と ) だけで構成された文字列 S が与えられます。任意の位置に最小限の括弧を追加して、結果として得られる文字列を「有効な括弧列」にすることを考えます。括弧列が有効であるとは、次のいずれかの条件を満たすことを指します。 空文字列である XY(X と Y を連結した形)と表せ、X と Y がどちらも有効な文字列である (A) という形で表せ、A が有効な文字列である たとえば、文字列が "()))((" の場合、これを有効にするには 4 つの括弧を追加する必要があります。 解法のアプローチ この問題はスタックの考え方を使うとシンプルに解決できます。具体的な