给定一个非空字符串,其中包含字母顺序打乱的英文单词表示的数字0-9。按升序输出原始的数字。
注意:
输入只包含小写英文字母。
输入保证合法并可以转换为原始的数字,这意味着像 “abc” 或 “zerone” 的输入是不允许的。
输入字符串的长度小于 50,000。
示例 1:
输入: “owoztneoer”
输出: “012” (zeroonetwo)
示例 2:
输入: “fviefuro”
输出: “45” (fourfive)
解题思路:
很有意思的一道题,我初看以为要用DFS,脑子里构思了一下DFS的代码,感觉非常复杂,即便写出来,也要废去很大的时间。于是转手偷个懒,去研究这道题的特征,有的放矢。因为我们只需要给出0-9的排序结果,又不是100以内的正整数,那我们不需要去建立一个能够通用的算法。
首先,我们用一个map<char,int>来保存所有字符及其对应的数量
然后,观察英文字母结果可知,0,2,4,6,8,这五个英文字母zero,two,four,six,eight,分别对应一个独一无二的字母:z,w,u,x,g
那我们可以根据这五个字符的数量,先判断出这五个数的数量,然后从原始数据中减去这五个数所带字符的数量。再判断剩下的数的数量。
观察剩下的英文字母可知,1,3,5,7,9,这五个英文字母one,three,five,seven,nine,也分别对应一个独一无二的字母:o,r,f,s,e(为什么说nine对应一个e呢,应为处理完前面所有的字符,剩下的e的数量也只能代表nine的数量了)。
于是我们可用这样的遍历顺序,去去除原始map中字符的数量,同时保存每个数字的数量,最后便可得到结果,代码如下:
28ms
class Solution {
public:
string originalDigits(string s) {
unordered_map<char, int>data;
for (auto i : s)
++data[i];
vector<pair<int, int>>result;
vector<pair<string, char>>work{ { "zero0",'z' },{ "two2",'w' },{ "four4",'u' },{ "six6",'x' },{ "eight8",'g' },
//我这里英文字母和数字放在一个string里保存了,原因是我不想再建立一个单词和数字的映射表了,省点代码,也省点内存。
for (auto i : work) {
wipeOff(data, i.first, i.second, result);
}
string res;
for (int i = 0; i<5; ++i) {
int num1 = result[i].first;
int count1 = result[i].second;
int num2 = result[i + 5].first;
int count2 = result[i + 5].second;
res += string(count1, '0' + num1);
res += string(count2, '0' + num2);
}
return res;
}
void wipeOff(unordered_map<char, int>& data, string oriStr, char c, vector<pair<int, int>>& result) {
int sz = oriStr.size();
string str = oriStr.substr(0, sz - 1);
string index = oriStr.substr(sz - 1);
int count = data[c];
if (count != 0) {
for (auto i : str) {
data[i] -= count;
}
}
result.push_back({ stoi(index),count });
}
};