Question
描述
易信是由網易和電信聯合開發的一款即時通訊軟件。除了語音聊天,免費電話等新功能以外,傳統的文字信息聊天功能也得以保留,因此每天都有大量的文字信息需要在服務器中存儲,中轉。
小Y是一名負責處理文字信息的易信工程師,每天他都要和字符串打交道。爲了提高存儲和傳輸效率,小Y在課餘時間經常會去研究字符串的存儲方法。通過內部使用的一種統一的加密算法,所有的文字信息首先都會被轉化成只包含大寫字母['A'...'Z']的字符串。爲了壓縮這個加密後的字符串,小Y最近想出了兩個存儲的規則:
(1)如果字符串中有連續相同的大寫字母,它們可以選擇用"字符+出現次數"的方式替代。如字符串'AABCCCCDD',可以用'A2BC4D2'表示,也可以用'A2BC2C2DD'表示。
(2)如果字符串中有連續出現的模式串(模式串長度大於1),它們可以選擇用"(模式)+出現次數"的方式替代。如字符串'FABCABCABCE',可以用'F(ABC)3E'表示,也可以用'F(ABC)2ABCE'表示。
上述規則中的"連續"均指出現次數大於1,規則(2)中的括號後一定是一個大於1的數值,代表出現次數。
綜合上述兩個規則,字符串'AABAABFAABAABFG'可以用'((A2B)2F)2G'表示。小Y保證輸出的壓縮串符合上述的兩個規則,以下類型的非法字符串不會出現:
'(A)5': 括號冗餘
'A1A4': 數字1冗餘
'A((AA))2': 括號冗餘
(ABC)1: 括號和數字1冗餘
對於給定的一個用上述規則壓縮後的字符串,對應的原串是唯一的。小Y想知道這個字符串原來的長度是多少,以此計算壓縮倍率。你能幫助他嗎?
輸入
第一行是整數T(T <= 100),表示下面有T組數據。之後T行,每行爲一組數據,每組數據爲一個字符串。
每個字符串只會包含26個大寫字母['A'...'Z'],數字['0'...'9']和左右括號['(', ')']。
保證輸入數據一定合法,括號內的模式串長度一定大於1,表示出現次數的數字一定大於1,且字符串長度L <= 100。
輸出
輸出T行,每行對應一個數據的輸出結果,表示字符串的實際長度。
保證每個字符串展開後的長度不超過109。
4 (AA)2A ((A2B)2)2G WANGYI A2BC4D2樣例輸出
5 13 6 9
My Solution
#include <iostream>
#include <vector>
#include <string>
using namespace std;
/*得到數字,並讓指針指向最後一個數*/
int getDig(const string& str, int& idx)
{
int dig = 0;
for (; idx < str.size(); ++idx)
{
if (str[idx] >= '0' && str[idx] <= '9') //數字
{
dig = dig * 10 + str[idx] - '0';
}
else // 不是數字
{
--idx;
break;
}
}
return dig;
}
int countLength(const string& str, int& idx)
{
int score = 0;
int sSub = 0;
for (; idx < str.size(); ++idx)
{
char c = str[idx];
if (c >= 'A' && c <= 'Z') //字符
{
++score;
}
else if (c == '(')
{
++idx;
sSub = countLength(str, idx);
}
else if (c == ')')
{
return score;
}
else // 數字
{
if (str[idx - 1] == ')') //跟在模式串後面
{
int dig = getDig(str, idx);
score += dig * sSub;
}
else
{
int dig = getDig(str, idx);
score += dig - 1;
}
}
}
return score;
}
int main()
{
/*讀取字符串*/
int t;
vector<string> lines;
cin >> t;
for (int i = 0; i < t; ++i)
{
string line;
cin >> line;
lines.push_back(line);
}
for (auto str : lines)
{
int start = 0;
cout << countLength(str, start) << endl;
}
return 0;
}