1. 程式人生 > >LeetCode筆記:299. Bulls and Cows

LeetCode筆記:299. Bulls and Cows

問題:

You are playing the following Bulls and Cows game with your friend: You write down a number and ask your friend to guess what the number is. Each time your friend makes a guess, you provide a hint that indicates how many digits in said guess match your secret number exactly in both digit and position (called “bulls”) and how many digits match the secret number but locate in the wrong position (called “cows”). Your friend will use successive guesses and hints to eventually derive the secret number.

For example:

Secret number: “1807”
Friend’s guess: “7810”

Hint: 1 bull and 3 cows. (The bull is 8, the cows are 0, 1 and 7.)

Write a function to return a hint according to the secret number and friend’s guess, use A to indicate the bulls and B to indicate the cows. In the above example, your function should return “1A3B”.

Please note that both secret number and friend’s guess may contain duplicate digits, for example:

Secret number: “1123”
Friend’s guess: “0111”

In this case, the 1st 1 in friend’s guess is a bull, the 2nd or 3rd 1 is a cow, and your function should return “1A1B”.

You may assume that the secret number and your friend’s guess only contain digits, and their lengths are always equal.

大意:

你和你的朋友玩下面這個Bulls and Cows的遊戲:你寫一個數字,然後問你的朋友去猜數字。每次你的朋友進行一次猜測,你都給他提示說有多少數字是數字與位置都正確的(成為bulls)以及多少數字是數字有但是位置不正確的(成為cows)。你的朋友會根據提示最終猜出數字來。

例子:

祕密數字:“1807”
朋友的猜測:“7810”

提示:1個bull以及3個cows。(bull是8,cows是0,1和7)

寫一個函式來根據祕密數字和朋友的額猜測來返回暗示,使用A表示bull,B表示cows。在上面的例子中,你的函式應該返回“1A3B”。

請注意祕密數字和朋友的猜測都可能包含重複的數字,比如:

祕密數字:“1123”
朋友的猜測:“0111”

這種情況下,朋友猜測中的第一個1是bull,第二和第三個1是cow,你的函式應該返回“1A1B”。

你可以假設祕密數字和朋友的猜測都只包含數字,並且長度相等。

思路:

這道題分兩步:

第一步找到bull,也就是數字和位置都正確的個數,這個直接迴圈比對兩個字元串同等位置的數字是否一樣就好,為了方便我們先全部轉換成陣列去比較,比較完了記錄下個數,還要記錄下有哪些位置的數字是bull,這樣第二步找cow的時候就不要再判斷了。

第二步找cow,再次迴圈朋友的猜測,這次我們要跳過那些是bull的位置,對不是bull的每一個數字,去迴圈祕密數字中的數進行判斷,判斷時要注意第一不能位置一樣,第二數字要相等,第三不能是祕密數字中已經是bull的位置。且找到以後除了增加cow數字外也要記錄下來在祕密數字中的位置,以後就不要再找了。

在第二次找的過程中要注意我們不能重複找祕密數字中的位置,也就是有一個新陣列要記錄祕密數字中已經被找到的數字,這時候和bull中的位置是不一樣的,所以要另外加一個數組,但是加的時候不能直接等於之前第一步記錄的陣列來建立,這樣在進行修改陣列的時候其實還是修改的第一個陣列,因為只是引用了一遍位置,要進行深複製,使用clone。

此外對於朋友猜測中的一個數組,只能找一個cow,不能迴圈找多個,所以找到一個以後直接break退出迴圈開始找下一個數字。

程式碼(Java):

public class Solution {
    public String getHint(String secret, String guess) {
        char[] secretArr = secret.toCharArray();
        char[] guessArr = guess.toCharArray();
        int[] bullArr = new int[guess.length()];
        int bull = 0;
        int cow = 0;
        for (int i = 0; i < guessArr.length; i++) {
            if (guessArr[i] == secretArr[i]) {
                bull ++;
                bullArr[i] = 1;
            }
        }
        int[] bullSecretArr = bullArr.clone();
        for (int i = 0; i < guessArr.length; i++) {
            if (bullArr[i] == 0) {
                for (int j = 0; j < secretArr.length; j++) {
                    if (i != j && guessArr[i] == secretArr[j] && bullSecretArr[j] == 0) {
                        cow++;
                        bullSecretArr[j] = 1;
                        break;
                    }
                }
            }
        }
        String result = String.valueOf(bull) + 'A' + String.valueOf(cow) + 'B';
        return result;
    }
}

他山之石:

public class Solution {
    public String getHint(String secret, String guess) {
        int[] a1 = new int[256];
        int[] a2 = new int[256];

        int count1 = 0, count2 = 0;

        for(int i = 0; i < secret.length(); i++){
            if(secret.charAt(i) == guess.charAt(i)) count1++;
            else{
                a1[secret.charAt(i)]++;
                a2[guess.charAt(i)]++;
            }
        }

        for(int i = 0; i < 255; i++){
            if(a1[i] == a2[i]) count2+=a1[i];
            else count2 += Math.min(a1[i],a2[i]);
        }

        return count1+"A"+count2+"B";
    }
}

這個做法第一步也是直接找bull,巧妙的地方在於第二步找cow數量的方法。在第一步中對於不是bull的位置的數字,分別都記錄下來對應位置的數字,對數字的數量進行累加,這樣迴圈一遍後就知道各自還有哪些數字沒找到,以及他們的個數。在找cow的時候,只需要對每個出現過的數字,取兩邊出現的較少的那一個數量即可,這樣也可以避免重複,很巧妙地減少了時間複雜度。