题目原址
题目描述
给你一个字符串 s ,其中包含字母顺序打乱的用英文单词表示的若干数字(0-9)。按升序返回原始的数字。
示例 :
输入:s = “owoztneoer”
输出:“012”
输入:s = “fviefuro”
输出:“45”
提示:
- 1 <= s.length <= 105
- s[i] 为 [“e”,“g”,“f”,“i”,“h”,“o”,“n”,“s”,“r”,“u”,“t”,“w”,“v”,“x”,“z”] 这些字符之一
- s 保证是一个符合题目要求的字符串
解题思路
- 建立哈希表,存放字符串中每个字符出现的次数,以此来判断数字对应的字符子串是否出出现。
- 编写检查函数,判断该数字是否出现。即将数字对应的每个字符去哈希表是否可以找到。如果每个字符都存在,则该数字可能存在。
这个可能是因为该数字每个字符都存在,但是有可能是其他数字的部分字符组成的。例如1的"one",o可能是"zero",“two”,“four"中的’o’,n可能是"seven",“nine"中的’n’,e可能是"three”,“five”,“seven”,“eight”,“nine”。 - 编写减函数reduce,如果数字出现,且将该数字存入了结果,则将哈希表中该数字的各个字符减1。
- 根据唯一性标识原则,建立检查数顺序vector ord = ***{0, 2, 4, 1, 3, 5, 6, 7, 8, 9}***该顺序保证了每个数字检查时,如果存在的话就一定是该数字。例如0的唯一性标识符时’z’,2的唯一性标识时’w’,1在0,2,4的后面,所以此时1的唯一性标识可以是’o’。以此类推,每个数字对应的字符都有唯一性标识,这可以 保证检查的时候该数字的每个字符都存在,则一定就是该数字也存在。
- 另外建立一个数组存re[10]放各数字出现的次数以及存放字符串的结果res。读取的时候只需从按数组地址0-9读出存入res中就是升序了。
代码
class Solution {
public:
vector<string> num = {"zero","one","two","three","four","five","six","seven","eight","nine"};
//检查该数字对应字母是否存在
bool check(int n,vector<int> &fre){
for(auto c : num[n])
if(fre[c - 'a'] == 0)
return false;
return true;
}
//减去相应数字对应的字符
void reduce(int n, vector<int> &fre){
for(auto c : num[n])
fre[c - 'a'] --;
}
string originalDigits(string s) {
string res; //记录最后的结果
vector<int> re(10, 0); //记录出现数字的次数
vector<int> fre(26, 0);//存放每个字符出现的次数
for (char c : s) //记录字符串s中各字母出现次数
fre[c - 'a']++;
//有"zero"必为0,z是唯一标识符,有"one"不一定为1,1没有唯一标识符,故要放在后面
//分析0-9数字,发现1,3应放在后面,另外"zero""two""four"去掉后,1的"one"中'o'就为唯一标识符了
vector<int> ord = {0, 2, 4, 1, 3, 5, 6, 7, 8, 9};
for(auto x : ord) //按特定顺序检查是否存在各数字
while(check(x,fre)){
reduce(x,fre);
re[x] ++;
}
for(int i = 0; i < 10 ; i ++)
//按顺序读出各数字
while(re[i]--){
char c = i + '0';
res += c;
}
return res;
}
};
总结
我是菜鸡,没什么好总结的,老luo用了一会儿,我花了一个小时才做出来。