# 299. Number guessing game

Keywords: leetcode

You are playing balls and cows with your friends. The rules of the game are as follows:

Write a secret number and ask your friend to guess what the number is. Every time a friend guesses, you will give him a hint containing the following information:

Guess how many digits in the number belong to the number and the exact position (called "Bulls", bull),
How many digits belong to numbers, but the position is wrong (called "Cows"). In other words, how many non bull numbers in this guess can be converted into bull numbers by rearrangement.

The format of the prompt is "xAyB", x is the number of bulls, y is the number of cows, A is the number of bulls, and B is the number of cows   Represents A cow.

Please note that both secret numbers and numbers guessed by friends may contain duplicate numbers.

Example 1:

Input: secret = "1807", guess = "7810"
Output: "1A3B"
Explanation: the numbers and positions are connected by '|' for (bulls). If the numbers are right and the positions are wrong (cows), they are marked in bold italics.
"1807"
|
"7810"
Example 2:

Input: secret = "1123", guess = "0111"
Output: "1A1B"
Explanation: the numbers and positions are connected by '|' for (bulls). If the numbers are right and the positions are wrong (cows), they are marked in bold italics.
"1123" "1123"
| or |
"0111" "0111"
Note that only one of the two mismatched ones will be counted as a cow (the number is guessed right and the position is wrong). By rearranging non bull numbers, only one 1 can become a bull number.
Example 3:

Input: secret = "1", guess = "0"
Output: "0A0B"
Example 4:

Input: secret = "1", guess = "1"
Output: "1A0B"

Tips:

1 <= secret.length, guess.length <= 1000
secret.length == guess.length
secret and guess consist only of numbers

Idea 1:

Dictionary + zipper method

Record the number and the position of occurrence in the dictionary, and calculate the values of A and B after traversing guess

``` 1 class Solution:
2     def getHint(self, secret: str, guess: str) -> str:
3         maps = {}
4         length = len(secret)
5         bull_mask = [False] * length
6         A = 0
7         B = 0
8         for i in range(length):
9             key = secret[i]
10             if key in maps:
11                 maps[key].append(i)
12             else:
13                 maps[key] = [i]
14
15         # bulls
16         for i in range(length):
17             guess_ch = guess[i]
18             if guess_ch in maps and i in maps[guess_ch]:
19                 A += 1
20                 maps[guess_ch].remove(i)
22
23         # cows
24         for i in range(length):
25             guess_ch = guess[i]
26             if not bull_mask[i] and guess_ch in maps and maps[guess_ch]:
27                 B += 1
28                 maps[guess_ch].pop()
29         return format(f"{A}A{B}B")```

Idea 2:

Considering that there are only 10 occurrences of numbers, you can simplify the dictionary into an array

A number corresponds to the number of cows   After excluding the bull, min(guess the number of times the number appears, and the number of times the number appears in secret)

``` 1 class Solution2:
2     def getHint(self, secret: str, guess: str) -> str:
3         A = 0
4         B = 0
5         cnt_secret =  * 10
6         cnt_guess =  * 10
7
8         for i in range(len(secret)):
9             guess_ch = guess[i]
10             secret_ch = secret[i]
11             # bulls
12             if guess_ch == secret_ch:
13                 A += 1
14             # cows
15             else:
16                 cnt_secret[ord(secret_ch) - ord('0')] += 1
17                 cnt_guess[ord(guess_ch) - ord('0')] += 1
18         for s, g in zip(cnt_secret, cnt_guess):
19             B += min(s, g)
20         return f"{A}A{B}B"```

Posted by rbastien on Sun, 07 Nov 2021 20:40:09 -0800