题目
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.
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.
Please note that both secret number and friend’s guess may contain duplicate digits.
Example 1:
Input: secret = “1807”, guess = “7810”
Output: “1A3B”
Explanation: 1 bull and 3 cows. The bull is 8, the cows are 0, 1 and 7.
Example 2:
Input: secret = “1123”, guess = “0111”
Output: “1A1B”
Explanation: The 1st 1 in friend’s guess is a bull, the 2nd or 3rd 1 is a cow.
思路
题中只使用数字,考虑用长度为10的数组先记录每个数字出现的次数,再次遍历。
- 若 g u e s s guess guess和 s e c r e t secret secret第i位相同则A的数量增加
- 不相同但 g u e s s guess guess中的数字在 s e c r e t secret secret中出现,B增加
看过第i位后减少数组记录的数量。
这样的话有一个问题, g u e s s guess guess会贪心的匹配 s e c r e t secret secret中处在i位后的相同数字,可能会导致 g u e s s [ i ] = s e c r e t [ i ] guess[i] = secret[i] guess[i]=secret[i]时,数组中记录的个数 r e s t [ i ] < = 0 rest[i] <= 0 rest[i]<=0。修改在判断相等后再次判断 r e s t [ i ] = = 0 rest[i] == 0 rest[i]==0,若成立则B减1。
举例
s
e
c
r
e
t
=
"
0122
"
,
g
u
e
s
s
=
"
2122
"
secret = "0122", guess = "2122"
secret="0122",guess="2122"
g
u
e
s
s
[
0
]
guess[0]
guess[0]会匹配
s
e
c
r
e
t
[
2
]
secret[2]
secret[2],
g
u
e
s
s
[
2
]
guess[2]
guess[2]会匹配
s
e
c
r
e
t
[
3
]
secret[3]
secret[3],到
i
=
3
i = 3
i=3时,此时
A
=
2
A = 2
A=2,
B
=
1
B = 1
B=1,比较后有
g
u
e
s
s
[
i
]
=
s
e
c
r
e
t
[
i
]
guess[i] = secret[i]
guess[i]=secret[i],但因为
r
e
s
t
[
2
]
=
=
0
rest[2] == 0
rest[2]==0,得到
A
=
3
A = 3
A=3,
B
=
0
B = 0
B=0。
代码
public String getHint(String secret, String guess) {
int A = 0, B = 0;
int[] rest = new int[10];
for (int i = 0; i < secret.length(); i++) {
rest[secret.charAt(i) - '0']++;
}
for (int i = 0; i < secret.length(); i++) {
//System.out.println(rest[guess.charAt(i) - '0']);
if (secret.charAt(i) == guess.charAt(i)) {
A++;
if (rest[guess.charAt(i) - '0'] == 0) {
B--; // 前面不对位置的多match了一个
} else {
rest[guess.charAt(i) - '0']--;
}
} else {
if (rest[guess.charAt(i) - '0'] != 0) {
B++;
rest[guess.charAt(i) - '0']--;
}
}
}
return String.format("%dA%dB", A, B);
}
优化
看了一下最快的代码,可以只遍历一遍,用两个数组记录出现频率, c o w cow cow的数量就是在每次遍历的时候比较是否有 g u e s s [ i ] guess[i] guess[i]存在于 s e c r e t secret secret的数组中(与之前位数匹配), s e c r e t [ i ] secret[i] secret[i]存在于 g u e s s guess guess的数组中(与之后位数匹配)。
同时 S t r i n g . f o r m a t ( ) String.format() String.format()比 S t r i n g B u i l d e r StringBuilder StringBuilder多花很多的时间和空间!
修改代码如下
public String getHint(String secret, String guess) {
int[] secretMap = new int[10];
int[] guessMap = new int[10];
int bull = 0;
int cow = 0;
for(int i = 0; i < secret.length(); i++) {
if(secret.charAt(i) == guess.charAt(i)) {
bull++;
} else {
int sDigit = secret.charAt(i) - '0';
int gDigit = guess.charAt(i) - '0';
if(guessMap[sDigit] > 0) {
guessMap[sDigit]--;
cow++;
} else {
secretMap[sDigit]++;
}
if(secretMap[gDigit] > 0) {
secretMap[gDigit]--;
cow++;
} else {
guessMap[gDigit]++;
}
}
}
StringBuilder sb = new StringBuilder();
sb.append(bull).append("A").append(cow).append("B");
return sb.toString();
}