エンコードされた文字列を指定すると、デコードされた文字列を返します。
エンコード規則は次のとおりですk[encoded_string]
。これは、角かっこがencoded_string
正確にk
何回繰り返されるかを意味します。k
正の整数であることが保証されていることに注意してください。
入力文字列は常に有効であり、入力文字列には余分なスペースがなく、入力角括弧は常に整形式であると想定できます。
また、元のデータには数字が含まれていないと考えることができます。すべての数字は繰り返しの数を表すだけです。k
たとえば、3a
やのような入力はありません2[4]
。
例1:
入力:s = "3 [a] 2 [bc]"
出力: "aaabcbc"
例2:
入力:s = "3 [a2 [c]]"
出力: "accaccacc"
アイデア:
入力文字列には角かっこがネストされている場合があります。このとき、最初に内側の角かっこで文字列をデコードし、次に外側の角かっこで文字列をデコードします。つまり、左から文字列をトラバースするときに移動します。そうです、[
最初にトラバースされた内部文字列は後でデコードされます。これは、ファーストイン、ラストアウトスタックの特性に沿っているため、スタックを使用してこの問題を解決できます。
入力文字列のトラバースは次のように実行されます。
- トラバーサルは数値であり、最初に完全な数値文字列を抽出してから、スタックをプッシュします。
- トラバーサルは文字または
'['
であり、スタックに直接プッシュされます。 - トラバーサルは、
']'
最初にコピーする文字列を取得してからコピーすることです。コピーした文字列をスタックにプッシュバックするのが最適です。
トラバースした場合']'
の具体的な操作手順は次のとおりです。
- 最初にスタックをポップし、ポップされた文字列をベクターに保存し、「[」がポップされるまでスタックのポップを停止し、「[」がベクターに保存されないようにします。
- 次に、ポップの順序がスタックの順序と反対であるため、ベクトルの内容を反転します。
- 次に、コピーするいくつかの文字列をスプライスして、コピーする最終的な文字列を取得します。
- この時点でスタックの一番上にある数値文字列をポップし、整数numに変換します。
- コピーする文字列をnum回コピーし、最後にコピーした文字列を取得します。
- コピーした文字列をスタックにプッシュします。
最後に、入力文字列がトラバースされると、スタック内の文字列をスプライスすることによって、最終的にデコードされた文字列が取得されます。
アニメーションデモ:
コードは次のとおりです。
class Solution {
public:
//从字符串s的pos位置开始,提取数字字符串
string GetNum(string& s, size_t& pos)
{
string num;
while (s[pos] != '[')
{
num += s[pos];
pos++;
}
return num;
}
//将vector当中的字符串拼接后进行返回
string GetString(vector<string>& st)
{
string s;
for (auto e : st)
{
s += e;
}
return s;
}
string decodeString(string s) {
vector<string> st; //数组模拟栈
size_t pos = 0; //用于遍历字符串s
while (pos < s.size())
{
//1、遍历到的是数字,先将完整的数字字符串提取出来,然后进行压栈
if (isdigit(s[pos]))
{
string num = GetNum(s, pos);
st.push_back(num);
}
//2、遍历到的是字母或'[',直接将其进行压栈
else if (isalpha(s[pos]) || s[pos] == '[')
{
st.push_back(string(1, s[pos]));
pos++;
}
//3、遍历到的是']',先获取到待复制的字符串,再将其进行复制,最好将复制后的字符串重新进行压栈
else
{
vector<string> sub; //待复制的若干字符串
//a、先进行弹栈,将弹出的字符串保存到vector当中,直到'['被弹出时停止弹栈,'['不保存到vector中
while (st.back() != "[")
{
sub.push_back(st.back());
st.pop_back();
}
st.pop_back();
//b、再将vector当中的内容进行逆置,因为出栈的顺序与入栈顺序相反
reverse(sub.begin(), sub.end());
//c、然后将待复制的若干字符串进行拼接,得到最终待复制的字符串
string all = GetString(sub);
//d、弹出此时栈顶的数字字符串,并将其转换成整数num
int num = stoi(st.back());
st.pop_back();
//d、将待复制的字符串复制num次,最终得到复制后的字符串
string str; //复制后的字符串
while (num--)
{
str += all;
}
//e、将复制后的字符串进行压栈
st.push_back(str);
pos++;
}
}
return GetString(st); //将栈当中的字符串拼接后进行返回
}
};
コードの説明:
- コードは実際のスタックを使用しませんが、スタックの最下部から最上位へのトラバーサルを容易にするために、ベクトルを使用してスタックのプッシュとポップをシミュレートします。(これは重要なポイントです)
- GetNum関数のパラメーターposは、文字列をトラバースするために常に同じpos変数を使用していることを確認するために、参照によって渡される必要があります。