题目
将中文数字转换为阿拉伯数字(详见《算法的乐趣》一书的 4.3 节)
示例:
输入:"十五"
输出:15
输入:"八百七十三亿九千零六十万五百八十七"
输出:87390600587
输入:"两万零一十"
输出:20010
解答 & 代码
中文数字以万为小节,**"亿"**
、**"万"**
是节权位,**"十"**
、**"百"**
、**"千"**
是普通权位
遍历中文数字:
- 如果当前是节权位,则需要将当前节的整体数值
secVal
乘上节权位对应的量级,加到result
- 如果当前是普通权位,则只需要将当前数值
curVal
乘上对应的权位,加到secVal
- 如果当前是数字,则转换为数字,赋值给
curVal
```cppinclude
include
include
include
using namespace std;
const int CHAR_LENGTH = 2; // GBK 编码一个中文字符占 2 个字节, 如果是 UTF-8 编码则一个中文字符占 3 个字节
long long ChineseToNumber(string chineseStr)
{
unordered_map
long long result = 0; // 结果,中文数字转换后的阿拉伯数字
long long secVal = 0; // 当前小节(以万为一个小节)的数值,即节权位之前的数值
long long curVal = 0; // 当前的数值,即普通权位之前的数值
for(int i = 0; i < chineseStr.size(); i += CHAR_LENGTH)
{
string ch = chineseStr.substr(i, CHAR_LENGTH); // 当前的汉字
// 如果当前汉字为权位
if(weightValMap.find(ch) != weightValMap.end())
{
if(ch == "万" || ch == "亿") // 如果是节权位:需要将当前节的整体数值 secVal 乘上节权位对应的量级,加到 result
{
secVal += curVal;
result += secVal * weightValMap[ch];
secVal = 0;
}
else // 如果是普通权位:需要将当前数值 curVal 乘上对应的权位,加到 secVal
{
curVal = curVal == 0 ? 1 : curVal; // 注意特殊情况:如果 curVal == 0 要设为 1,不然如果输入"十五",输出是 5 而不是 15
secVal += curVal * weightValMap[ch];
}
curVal = 0;
}
// 当前汉字为普通数字,转换为数字
else if(numValMap.find(ch) != numValMap.end())
curVal = numValMap[ch];
}
// 最后加上最后一小节的值
result += secVal + curVal;
return result;
}
struct TEST_DATA { string chineseStr; long long number; };
int main()
{
vector
for(int i = 0; i < testPairList.size(); ++i)
{
string chineseStr = testPairList[i].chineseStr;
long long targetNum = testPairList[i].number;
long long result = ChineseToNumber(chineseStr);
if(result != targetNum)
cout << chineseStr << ", " << targetNum << ", " << result << endl;
}
cout << "finished..." << endl;
return 0;
}
``` 复杂度分析:设字符串长为 n
- 时间复杂度 O(n):
- 空间复杂度 O(1):