一、题目描述
你在和朋友一起玩 猜数字(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 可以成为公牛数字。
提示:
1 <= secret.length, guess.length <= 1000
secret.length == guess.length
secret
和guess
仅由数字组成
二、解题思路
- 遍历 secret 和 guess 字符串,比较每一位字符是否相同。如果相同,则公牛(Bulls)数量加一。
- 使用一个长度为 10 的数组(记为 cnt)来记录 secret 中每一位数字出现的次数(0-9),以及 guess 中每一位数字出现的次数。
- 再次遍历 secret 和 guess 字符串,如果字符不同,则分别将它们在 cnt 数组中的对应位置加一。
- 遍历 cnt 数组,对于每一位数字,取其在 secret 和 guess 中出现次数的较小值,累加到奶牛(Cows)数量上。
- 根据公牛和奶牛的数量,构造并返回结果字符串。
三、具体代码
class Solution {
public String getHint(String secret, String guess) {
int bulls = 0; // 公牛数量
int cows = 0; // 奶牛数量
int[] cntS = new int[10]; // secret 中数字出现的次数
int[] cntG = new int[10]; // guess 中数字出现的次数
for (int i = 0; i < secret.length(); i++) {
char s = secret.charAt(i);
char g = guess.charAt(i);
if (s == g) {
bulls++; // 数字和位置都猜对了,公牛数量加一
} else {
cntS[s - '0']++; // secret 中对应数字出现次数加一
cntG[g - '0']++; // guess 中对应数字出现次数加一
}
}
for (int i = 0; i < 10; i++) {
cows += Math.min(cntS[i], cntG[i]); // 取 secret 和 guess 中对应数字出现次数的较小值,累加到奶牛数量上
}
return bulls + "A" + cows + "B"; // 构造并返回结果字符串
}
}
四、时间复杂度和空间复杂度
1. 时间复杂度
-
第一个
for
循环遍历了字符串secret
和guess
一次,其长度为n
(假设两个字符串长度相等),因此这个循环的时间复杂度为 O(n)。 -
第二个
for
循环遍历了一个长度为 10 的固定数组,因此这个循环的时间复杂度为 O(1),因为循环次数是常数。
由于两个循环是顺序执行的,总的时间复杂度就是两个循环时间复杂度的和,即 O(n) + O(1) = O(n)。
2. 空间复杂度
-
bulls
和cows
是两个整型变量,它们占用的空间是常数,即 O(1)。 -
cntS
和cntG
是两个长度为 10 的整型数组,它们占用的空间也是常数,即 O(1)。
由于我们只使用了固定大小的额外空间,不随输入字符串长度的增加而增加,因此总的空间复杂度为 O(1)。
五、总结知识点
-
类定义:
class Solution
定义了一个名为Solution
的类。 -
方法定义:
public String getHint(String secret, String guess)
定义了一个公共方法getHint
,它接受两个字符串参数并返回一个字符串。 -
基本数据类型:
int
用于定义整数变量bulls
和cows
,用于存储公牛和奶牛的数量。 -
数组:
int[] cntS
和int[] cntG
定义了两个整型数组,用于记录secret
和guess
中每个数字出现的次数。 -
循环结构:
for
循环用于遍历字符串和数组。第一个for
循环用于遍历字符串secret
和guess
,第二个for
循环用于遍历长度为 10 的数组。 -
字符操作:使用
charAt(int index)
方法从字符串中获取指定位置的字符。 -
字符与整数的转换:通过
'0'
将字符转换为对应的整数(例如,'0'
-> 0,'1'
-> 1, …)。 -
条件语句:
if
语句用于检查两个字符是否相等,从而确定是否为公牛。 -
数组操作:数组元素通过索引访问,并进行递增操作以记录数字出现的次数。
-
数学函数:
Math.min(int a, int b)
用于计算两个整数中的最小值。 -
字符串拼接:使用
+
运算符将整数转换为字符串,并与其他字符串拼接构造最终的返回结果。 -
方法返回值:使用
return
语句返回方法的结果。
以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。