您的位置:首页 > 其它

[LeetCode] 423. Reconstruct Original Digits from English 解题报告

2017-02-17 05:09 471 查看
Given a non-empty string containing an out-of-order English representation of digits 
0-9
,
output the digits in ascending order.

Note:

Input contains only lowercase English letters.
Input is guaranteed to be valid and can be transformed to its original digits. That means invalid inputs such as "abc" or "zerone" are not permitted.
Input length is less than 50,000.

Example 1:

Input: "owoztneoer"

Output: "012"


Example 2:

Input: "fviefuro"

Output: "45"


这个题目咋看之下还是有点麻烦,网友提到用穷举加上回溯来做。但是针对这一题,由于题目里面已经交代了输入的序列一定是有效的,我想到一个非常巧妙的方法,不具有通用性。
思路:
由于字母的总数我们是知道的,所以开始我们可以用一个数组int[26]来记录下每个字母的数量,接下来我们根据这个,可以来推断每个单词有多少个。
仔细分析我们可以发现,有5个单词,都存在一个特定的字母,在这10个单词里面只有它自己有,比如:"zero"->z, "two"->w, "four"->u, "six"->x,"eight"->g,比如对于zero来说,z只有它有,其他的单词没有。换句话说,我只要知道一共有多少个z,就知道有多少个zero。同理,对于two,我只要知道有多少个w,就知道有多少个two。
所以,先算这个5个单词,这5个特定的字母,从int[26]里面获取特定字母的个数,然后将其他字母的数量减去这个数量就可以了。比如,先算zero,发现z有5个,然后最后的结果肯定有5个0,如果e有11个,那么11-5=6,算完zero以后,e就只有6个,以此类推即可。
当然,这前5个单词是顺序不分先后的。接下来,算的单词就必须保证顺序了,我们只要找到接下来拥有独一无的字母的单词就可以算了。比如,接下来算five,因为f只有four和five有,four在前面一句算过了,现在算five就好了。同理,后面的顺序是,five,seven,one,three,nine。
然后根据算出来的结果,每个数字对应几个,拼出结果就好。代码如下,复杂度大致为O(N),确实只需要一次遍历即可,这个方法打败了95.94%的提交:

public class Solution {
public String originalDigits(String s) {
StringBuilder sb = new StringBuilder();
char[] cArs = s.toCharArray();
int[] nArrChars = new int[26];
for (char c : cArs) {
nArrChars[c - 'a']++;
}
int[] nArrResult = new int[10];
// "zero"->z, "two"->w, "four"->u, "six"->x, "eight"->g
nArrResult[0] = nArrChars['z' - 'a'];
minusDigits(nArrChars, "zero", nArrResult[0]);
nArrResult[2] = nArrChars['w' - 'a'];
minusDigits(nArrChars, "two", nArrResult[2]);
nArrResult[4] = nArrChars['u' - 'a'];
minusDigits(nArrChars, "four", nArrResult[4]);
nArrResult[6] = nArrChars['x' - 'a'];
minusDigits(nArrChars, "six", nArrResult[6]);
nArrResult[8] = nArrChars['g' - 'a'];
minusDigits(nArrChars, "eight", nArrResult[8]);
// "five"->f, "seven"->v, "one"->o
nArrResult[5] = nArrChars['f' - 'a'];
minusDigits(nArrChars, "five", nArrResult[5]);
nArrResult[7] = nArrChars['v' - 'a'];
minusDigits(nArrChars, "seven", nArrResult[7]);
nArrResult[1] = nArrChars['o' - 'a'];
minusDigits(nArrChars, "one", nArrResult[1]);
// "three"->t, "nine"->i
nArrResult[3] = nArrChars['t' - 'a'];
minusDigits(nArrChars, "three", nArrResult[3]);
nArrResult[9] = nArrChars['i' - 'a'];
minusDigits(nArrChars, "nine", nArrResult[9]);

// add all number
for (int i = 0; i < nArrResult.length; i++) {
for (int j = 0; j < nArrResult[i]; j++) {
sb.append((char) (i + (int) '0'));
}
}

return sb.toString();
}

private void minusDigits(int[] nArr, String str, int value) {
char[] cArr = str.toCharArray();
for (char c : cArr) {
nArr[c - 'a'] -= value;
}
}
}
以上代码有些冗余,实际上可以把这样的序列存起来,用一个循环解决就好,如下:

public class Solution {
private static final String[] NUMBERS_STRING = { "zero", "two", "four", "six", "eight", "five", "seven", "one",
"three", "nine" };
private static final char[] DIGITS = { 'z', 'w', 'u', 'x', 'g', 'f', 'v', 'o', 't', 'i' };
private static final int[] NUMBERS = { 0, 2, 4, 6, 8, 5, 7, 1, 3, 9 };

public String originalDigits(String s) {
StringBuilder sb = new StringBuilder();
char[] cArs = s.toCharArray();
int[] nArrChars = new int[26];
for (char c : cArs) {
nArrChars[c - 'a']++;
}
int[] nArrResult = new int[10];
for (int i = 0; i < 10; i++) {
nArrResult[NUMBERS[i]] = nArrChars[DIGITS[i] - 'a'];
minusDigits(nArrChars, NUMBERS_STRING[i], nArrResult[NUMBERS[i]]);
}
// add all number
for (int i = 0; i < nArrResult.length; i++) {
for (int j = 0; j < nArrResult[i]; j++) {
sb.append((char) (i + (int) '0'));
}
}

return sb.toString();
}

private void minusDigits(int[] nArr, String str, int value) {
char[] cArr = str.toCharArray();
for (char c : cArr) {
nArr[c - 'a'] -= value;
}
}
}


这里使用StringBuilder进行字符串拼接当然会效率更高。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode