leetcode面试题 17.07. 婴儿名字。之前写过一篇根本不算HASH的HASH,现在借鉴了各位大神的UT哈希方法,把这个题目理一理。
思路如下:
1、通过info存取names的关键信息,本质就是比names多了cnt及root信息,用处是记录最终的cnt信息,以及给团队赋值为最小字典序(char *root)
2、通过hash存取names的关键信息,用处是支撑synonyms元素的快速查找对应索引位置HASH_FIND,将两个索引进行并查集处理
小知识点一:对字符串分割
names = [“John(15)”,“Jon(12)”,“Chris(13)”,“Kris(4)”,“Christopher(19)”]
synonyms = ["(Jon,John)","(John,Johnny)","(Chris,Kris)","(Chris,Christopher)"]
分割方法依次如下,其中对字符串的分割停止表达是:%[^ xxx], xxx就是想停止的字符
sscanf(names[i],"%[^(](%d)", info[i].name, &cnt);
sscanf(syn,"(%[^,],%[^)])", tmps[0], tmps[1]);
小知识点二:UT哈希方法
1、建立HASH
hash_st *pool;
hash_st *head;
pool = (hash_st *)malloc(namesSize * sizeof(hash_st));
head = NULL;
2、查找&添加
遗留为什么这里用的HASH_FIND,如下链接总结了UT哈希
hash_st *new = &pool[psize];
new->key = info[i].name;
new->id = i;
hash_st *tmph;
HASH_FIND_STR(head, new->key, tmph);
if(tmph == NULL) {
HASH_ADD_KEYPTR(hh, head, new->key, tmplen, new);
psize++;
}
3、查找具体索引
hash_st *tmph;
HASH_FIND_STR(head, tmps[j], tmph);
if(tmph == NULL){
find = false;
break;
}
id[j] = tmph->id;
完整代码如下:
#define STR_LEN 50
typedef struct _info_st
{
char name[STR_LEN];
char *root;
int cnt;
}info_st;
typedef struct _hash_st
{
char *key;
int id;
UT_hash_handle hh;
}hash_st;
info_st *info;
hash_st *pool;
hash_st *head;
void InitialFa(int *fa, int len)
{
for(int i = 0; i < len; i++) {
fa[i] = i;
}
}
int FindFather(int *fa, int i) {
if(fa[i] == i) {
return i;
}
int son = i;
while(fa[i] != i) {
i = fa[i];
}
int tmp;
while(fa[son] != son) {
tmp = fa[son];
fa[son] = i;
son = tmp;
}
return i;
}
void Set(int* fa, int i, int j) {
int xx = FindFather(fa, i);
int yy = FindFather(fa, j);
if (xx != yy) {
fa[yy] = xx;
}
}
void InitialInfoHash(char** names, int namesSize)
{
int psize = 0;
int i, cnt, tmplen;
info = (info_st *)malloc(namesSize * sizeof(info_st));
pool = (hash_st *)malloc(namesSize * sizeof(hash_st));
head = NULL;
for (i = 0; i < namesSize; i++) {
sscanf(names[i],"%[^(](%d)", info[i].name, &cnt);
tmplen = strlen(info[i].name);
info[i].root = info[i].name;
info[i].cnt = cnt;
hash_st *new = &pool[psize];
new->key = info[i].name;
new->id = i;
hash_st *tmph;
HASH_FIND_STR(head, new->key, tmph);
if(tmph == NULL) {
HASH_ADD_KEYPTR(hh, head, new->key, tmplen, new);
psize++;
}
}
}
void Conbine(int*fa, const char * syn)
{
char tmps[2][STR_LEN];
int id[2];
bool find = true;
int j;
sscanf(syn,"(%[^,],%[^)])", tmps[0], tmps[1]);
for (j = 0; j < 2; j++) {
hash_st *tmph;
HASH_FIND_STR(head, tmps[j], tmph);
if(tmph == NULL){
find = false;
break;
}
id[j] = tmph->id;
}
if (find != true) {
return;
}
Set(fa, id[0], id[1]);
}
char** trulyMostPopular(char** names, int namesSize, char** synonyms, int synonymsSize, int* returnSize){
InitialInfoHash(names, namesSize);
int *fa = (int *)malloc(namesSize * sizeof(int));
InitialFa(fa, namesSize);
int i;
for(int i = 0; i < synonymsSize; i++) {
Conbine(fa, synonyms[i]);
}
int rsize = 0;
for(int i = 0; i < namesSize; i++)
{
int ff = FindFather(fa, i);
if(strcmp(info[i].name, info[ff].root) < 0){
info[ff].root = info[i].name;
}
if(i == ff) {
rsize++;
continue;
}
info[ff].cnt += info[i].cnt;
}
char **ret = (char **)malloc(rsize * sizeof(char *));
rsize = 0;
for(i = 0; i < namesSize; i++) {
if(i == FindFather(fa, i)){
ret[rsize] = malloc((sizeof(info[i].root) + 10) * sizeof(char));
sprintf(ret[rsize], "%s(%d)", info[i].root, info[i].cnt);
rsize++;
}
}
*returnSize = rsize;
return ret;
}