299. 猜数字游戏
你在和朋友一起玩 猜数字(Bulls and Cows)游戏,该游戏规则如下:
写出一个秘密数字,并请朋友猜这个数字是多少。朋友每猜测一次,你就会给他一个包含下述信息的提示:
猜测数字中有多少位属于数字和确切位置都猜对了(称为 “Bulls”,公牛),
有多少位属于数字猜对了但是位置不对(称为 “Cows”,奶牛)。也就是说,这次猜测中有多少位非公牛数字可以通过重新排列转换成公牛数字。
给你一个秘密数字 secret 和朋友猜测的数字 guess ,请你返回对朋友这次猜测的提示。
提示的格式为 “xAyB” ,x 是公牛个数, y 是奶牛个数,A 表示公牛,B 表示奶牛。
请注意秘密数字和朋友猜测的数字都可能含有重复数字。
示例 1:
输入:secret = "1807", guess = "7810"
输出:"1A3B"
解释:数字和位置都对(公牛)用 '|' 连接,数字猜对位置不对(奶牛)的采用斜体加粗标识。
"1807"
|
"7810"
示例 2:
输入:secret = "1123", guess = "0111"
输出:"1A1B"
解释:数字和位置都对(公牛)用 '|' 连接,数字猜对位置不对(奶牛)的采用斜体加粗标识。
"1123" "1123"
| or |
"0111" "0111"
注意,两个不匹配的 1 中,只有一个会算作奶牛(数字猜对位置不对)。通过重新排列非公牛数字,其中仅有一个 1 可以成为公牛数字。
示例 3:
输入:secret = "1", guess = "0"
输出:"0A0B"
示例 4:
输入:secret = "1", guess = "1"
输出:"1A0B"
提示:
1 <= secret.length, guess.length <= 1000
secret.length == guess.length
secret 和 guess 仅由数字组成
思考1:
- 初始思考是我们先得到A的个系数,接着对于对应相同的位置我们将两个字符串此位置的字符都替换为‘
’,这样的话再建立两个哈希表遍历两个改变后的字符串,计算其此时分别含有0-9字符个数,即可得到B的系数,因此可返回答案。 - 但是这样发现代码冗余很多,需要三次循环,并且还需要两个
StringBuilder
,并且还使用了replace
替换操作改变了两个字符串本身。
代码:
class Solution {
public String getHint(String secret, String guess) {
StringBuilder s1 = new StringBuilder(secret);
StringBuilder s2 = new StringBuilder(guess);
int[] hash1 = new int[10];
int[] hash2 = new int[10];
int num1 = 0;
int num2 = 0;
for(int i=0;i<secret.length();i++){
if(secret.charAt(i)==guess.charAt(i)){
num1++;
s1.replace(i,i+1," ");
s2.replace(i,i+1," ");
}
}
String s3 = s1.toString();
String s4 = s2.toString();
for(int i=0;i<secret.length();i++){
if(s3.charAt(i)==' '){
continue;
}
hash1[s3.charAt(i)-'0']++;
hash2[s4.charAt(i)-'0']++;
}
for(int i=0;i<10;i++){
if(hash1[i]!=0 && hash2[i]!=0){
num2 += Math.min(hash2[i],hash1[i]);
}
}
String res = "" + num1 + "A" + num2 + "B";
return res;
}
}
思考2:
摈弃更改原字符串的操作,不使用replace操作来记住字符相同的下标位置,而是再次利用哈希思想,使用一个公有数组pub
来记录公有字符的下标,且由于我们使用哈希的思想
来记录,即对于下标i
位置有公有字符,那么将pub[i] 的值置为1
,这样在对哈希表
进行存储时也刚好能直接由下标直接判断出该位置是否为公有位置,而不是直接利用pub数组
存储公有下标,那样的话我们还需要再套一个循环去pub数组
中查。
代码:
class Solution {
public String getHint(String secret, String guess) {
int[] hash1 = new int[10];
int[] hash2 = new int[10];
int[] pub = new int[secret.length()];
int num1 = 0;
int num2 = 0;
for(int i=0;i<secret.length();i++){
if(secret.charAt(i)==guess.charAt(i)){
num1++;
pub[i] = 1;
}
}
for(int i=0;i<secret.length();i++){
if(pub[i]==1){
continue;
}
hash1[secret.charAt(i)-'0']++;
hash2[guess.charAt(i)-'0']++;
}
for(int i=0;i<10;i++){
if(hash1[i]!=0 && hash2[i]!=0){
num2 += Math.min(hash2[i],hash1[i]);
}
}
String res = "" + num1 + "A" + num2 + "B";
return res;
}
}
思考3:
其实前面两层循环发现是可以放在一起的,他们没有后效性和延时性。判断出为公有位置后直接continue即可。
正是由于他的无后效性,我们后面发现其实pub数组的建立没啥用,我们直接设一个变量来判断其实就行了哈…
代码1:
class Solution {
public String getHint(String secret, String guess) {
int[] hash1 = new int[10];
int[] hash2 = new int[10];
int[] pub = new int[secret.length()];
int num1 = 0;
int num2 = 0;
for(int i=0;i<secret.length();i++){
if(secret.charAt(i)==guess.charAt(i)){
num1++;
pub[i] = 1;
}
if(pub[i]==1){
continue;
}
hash1[secret.charAt(i)-'0']++;
hash2[guess.charAt(i)-'0']++;
}
for(int i=0;i<10;i++){
if(hash1[i]!=0 && hash2[i]!=0){
num2 += Math.min(hash2[i],hash1[i]);
}
}
String res = "" + num1 + "A" + num2 + "B";
return res;
}
}
代码2:
class Solution {
public String getHint(String secret, String guess) {
int[] hash1 = new int[10];
int[] hash2 = new int[10];
int num1 = 0;
int num2 = 0;
for(int i=0;i<secret.length();i++){
boolean flag = false;
if(secret.charAt(i)==guess.charAt(i)){
num1++;
flag = true;
}
if(flag){
continue;
}
hash1[secret.charAt(i)-'0']++;
hash2[guess.charAt(i)-'0']++;
}
for(int i=0;i<10;i++){
if(hash1[i]!=0 && hash2[i]!=0){
num2 += Math.min(hash2[i],hash1[i]);
}
}
String res = "" + num1 + "A" + num2 + "B";
return res;
}
}