题目
将中文数字转换为阿拉伯数字(详见《算法的乐趣》一书的 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 而不是 15secVal += 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):
