思路:对于公牛很简单,循环数组判断即可,母牛的话,首先想的是一个作为Set另外往里add,但是两者都有重复就对不上了,比如1122和2211,看了下解题思路,使用哈希表进行词频统计,低的那个即是母牛的答案(因为两次不匹配只会算一次)
public static String getHint(String secret, String guess) {
//在ASCII编码中, 0~9 的编码是 0x30(48D)~0x39(57D),
// 所以当c在‘0'~'9'的范围中时,c - '0' 就相当于计算c的实际数值,
// 例如 c 是 '1', 则 c - '0' = 1, 把字符值转为数字值了
int length = guess.length();
int[] seHash = new int[10];
int[] guHash = new int[10];
int a = 0; int b = 0;
for(int i = 0 ; i < length; i++){
int se = secret.charAt(i) - '0';
int gu = guess.charAt(i) - '0';
if(se == gu){
a++;
}else{
seHash[se]++;
guHash[gu]++;
}
}
for(int i = 0 ; i < 10; i++){
b += Math.min(seHash[i],guHash[i]);
}
return a+"A"+b+"B";
}
哈希表学习
这道题的关键是活用哈希表,先重新复习了下什么是哈希表
哈希表也叫散列表,是根据键(Key)而直接访问在内存存储位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做散列表。
也就是说将存入的数据,根据某个函数进行计算,得出一个key,再通过key存放真正要存放的数据,就像数据的下标,根据下标访问效率会很快。
不过一般使用的HashMap存储的都是键值对,所以可以理解为通过键值对的键值算出一个数组下标,根据数组下标,将对应的entry存入,下次查找时,只需要根据entry的key通过同样的散列函数算出下标,获取的时候就非常的快。
哈希冲突
通过散列函数算出的下标如果出现重复,那就称之为哈希冲突,处理方法一个是开放寻址法,一个是拉链法
开放寻址法:
简单来说,当算出的下标为2的时候,发现下标为2的地方已经被占用,那就自动选择下一个地方,比如下标为3,如果为3再继续往下找,直到找到一个空地方为止
ThreadLocal用的就是开放寻执法
拉链法:
在被占用的地方的数据后面,增加一个链表,即每个Entry后面增加存储下一个数据的指针地址,下次查找时,只需要遍历链表即可。
HashMap用的就是拉链法
关于HashMap又有两个知识点:
1、当哈希表后面的链表过长时,遍历是非常耗时的,为了提高效率,当链表长度为8时会自动将该链表转为红黑树
2、当占用容量越多,哈希冲突发生的可能性就越大,为了避免频繁发生哈希冲突,会在占用率达到一定比例时进行扩容,这个比例称之为在HashMap里负载因子,源码里是0.75,而HashMapm默认大小是16,所以当占有率达到12时,就会进行扩容
回到题目
该解题思路是创了两个哈希表,因为数字只可能有10个(0~9),所以直接将数字作为key(虽然没有经历过散列函数的处理,但因为唯一的所以并没问题),再将出现的频率每次增加一即可。
跟Redis里的incr key是一样的处理方式