@NewWorld
2016-04-10T11:31:55.000000Z
字数 4058
阅读 2083
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 3public 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 4public 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 5public 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 6public 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";}