@NewWorld
2016-04-10T11:31:55.000000Z
字数 4058
阅读 2003
LeetCode
论文暂告一段落,闲着无聊到 LeetCode 刷刷题,蛤蛤蛤。
题目链接:Bulls and Cows
题目大意如下:
先给出一个数字串secret,再给出一个长度一样的猜测数字串guess。
对guess某个位置上的数字,若在secret串中的相同位置上存在相同的数字,则输出 1A,若有两个这种情况,则输出 2A;
当猜测数字串中除去完全匹配上位置的数字外,还有只猜中数字的情况,则猜中一个记为 1B,猜中两个记为 2B,secret中的数字不能被计数超过一次。
example 1 :
Secret number: "1807"
Friend's guess: "7810"
Output: 1A3Bexample 2 :
Secret number: "1123"
Friend's guess: "0111"
Output: 1A1B
为了达到 excited 的效果,当然是挑 easy 做,第一版代码如下:
// Version 汪
public static String getHint1(String secret, String guess) {
Set<Integer> indexListA = new HashSet<>();
Set<Integer> indexListB = new HashSet<>();
int length = guess.length();
for (int i=0; i<length; i++) {
if ((secret.charAt(i)^guess.charAt(i)) == 0) {
indexListA.add(i);
}
}
for (int i=0; i<length; i++) {
if (indexListA.contains(i)) {
continue;
}
for (int j=0; j<length; j++) {
if (indexListA.contains(j) || indexListB.contains(j)) {
continue;
}
if ((secret.charAt(i)^guess.charAt(j)) == 0) {
indexListB.add(j);
break;
}
}
}
return indexListA.size()+"A"+indexListB.size()+"B";
}
将运行过程分为了两部分,第一部分针对完全匹配的情况,第二部分针对只猜对数字的情况。提交以后运行效果惨不忍睹,与主流运行效果形成了强烈的反差(一开始可是用的 ArrayList)。进行改进,琢磨着去掉老是去 HashSet 中进行查询的行为,得到第二版:
// Version 吐
public static String getHint2(String secret, String guess) {
char[] secrets = secret.toCharArray();
char[] guesses = guess.toCharArray();
int numA = 0, numB = 0;
int length = guess.length();
for (int i=0; i<length; i++) {
if (secrets[i] == guesses[i]) {
numA++;
secrets[i] = 'a';
guesses[i] = 'a';
}
}
for (int i=0; i<length; i++) {
if (secrets[i] == 'a') {
continue;
}
for (int j=0; j<length; j++) {
if (guesses[j] == 'a') {
continue;
}
if (secrets[i] == guesses[j]) {
numB++;
secrets[i] = 'a';
guesses[j] = 'a';
break;
}
}
}
return numA+"A"+numB+"B";
}
主要是将字符串转为了一个字符数组,在字符数组中动手脚,标记已经匹配过的数字。然而提交后运行效果还是不理想。接着改进,发现第一部分发现完全匹配后,完全可以将匹配上的的数字丢弃掉,得到第三版:
// Version 3
public static String getHint3(String secret, String guess) {
char[] secrets = secret.toCharArray();
char[] guesses = guess.toCharArray();
int numA = 0, numB = 0;
int length = guesses.length;
for (int i=0; i<length; i++) {
while (secrets[i] == guesses[i]) {
numA++;
if (i == length-1) {
length--;
break;
}
secrets[i] = secrets[--length];
guesses[i] = guesses[length];
}
}
if (length == 0) {
return numA+"A0B";
}
for (int i=0; i<length; i++) {
for (int j=0; j<length; j++) {
if (guesses[j] == 'a') {
continue;
}
if (secrets[i] == guesses[j]) {
numB++;
secrets[i] = 'a';
guesses[j] = 'a';
break;
}
}
}
return numA+"A"+numB+"B";
}
这样在完全匹配后,同时减少了 secret 串和 guess 串的长度,后面的查找次数被缩短了。突然发现,既然第一部分可以丢弃数字,第二部分也可以丢弃,得到第四版:
// Version 4
public static String getHint4(String secret, String guess) {
char[] secrets = secret.toCharArray();
char[] guesses = guess.toCharArray();
int numA = 0, numB = 0;
int length = guesses.length;
for (int i=0; i<length; i++) {
while (secrets[i] == guesses[i]) {
numA++;
if (i == length-1) {
length--;
break;
}
secrets[i] = secrets[--length];
guesses[i] = guesses[length];
}
}
if (length == 0) {
return numA+"A0B";
}
int lengthS = length;
for (int i=0; i<length; i++) {
for (int j=0; j<lengthS; j++) {
if (secrets[j] == guesses[i]) {
numB++;
lengthS--;
if (lengthS == 0) {
return numA+"A"+numB+"B";
}
secrets[j] = secrets[lengthS];
break;
}
}
}
return numA+"A"+numB+"B";
}
主要的改进就是在第二部分中丢弃 secret 串中已经匹配上的数字。这次提交后击败了30%左右的 javasubmissions,然而和第一仍然相差甚远。一定还有更好的方法,接着思索,发现在第二部分的时候已经不需要顾忌数字在串中的位置了,那么,叮!直接计算每个串中数字出现的次数,然后取较小就行。而且关键是数字只有 0-9,哈哈,那就好办了。
// Versino 5
public static String getHint5(String secret, String guess) {
char[] secrets = secret.toCharArray();
char[] guesses = guess.toCharArray();
int numA = 0, numB = 0;
int length = guesses.length;
for (int i=0; i<length; i++) {
while (secrets[i] == guesses[i]) {
numA++;
if (i == length-1) {
length--;
break;
}
secrets[i] = secrets[--length];
guesses[i] = guesses[length];
}
}
if (length == 0) {
return numA+"A0B";
}
int[] countS = new int[10];
int[] countG = new int[10];
for (int i=0; i<length; i++) {
countS[secrets[i]-'0']++;
countG[guesses[i]-'0']++;
}
for (int i=0; i<countS.length; i++){
numB += countS[i] > countG[i] ? countG[i] : countS[i];
}
return numA+"A"+numB+"B";
}
麻蛋,猛然发现其实可以这样,不折腾...
运行效果与第五版相同。果然还是太 naive 啊。
// Version 6
public static String getHint6(String secret, String guess) {
char[] secrets = secret.toCharArray();
char[] guesses = guess.toCharArray();
int numA = 0, numB = 0;
int length = guesses.length;
for (int i = 0; i < length; i++) {
if (secrets[i] == guesses[i]) {
numA++;
}
}
int[] countS = new int[10];
int[] countG = new int[10];
for (int i = 0; i < length; i++) {
countS[secrets[i] - '0']++;
countG[guesses[i] - '0']++;
}
for (int i = 0; i < countS.length; i++) {
numB += countS[i] > countG[i] ? countG[i] : countS[i];
}
return numA + "A" + (numB - numA) + "B";
}