leecode刷题算法总结----哈希表(C语言)

附:C语言哈希表uthash的使用方法详解(附下载链接)

leecode刷题算法总结----哈希表

一、哈希表常用函数

结构构建

//哈希表结构体的构建
//1、key值为int型
struct HashEntry_int {
    int key;                    /* key */
    UT_hash_handle hh;         /* makes this structure hashable */
};
//2、key值为字符串
struct HashEntry_str {
    char* key;                    /* key */
    UT_hash_handle hh;         /* makes this structure hashable */
};
//3、key值为万能值(这里用long long代替)
struct HashEntry_ll {
    long long key;                    /* key */
    UT_hash_handle hh;         /* makes this structure hashable */
};

哈希表增加

//HASH_ADD_INT表示添加的键值为int类型
//HASH_ADD_STR表示添加的键值为字符串类型
//HASH_ADD_PTR表示添加的键值为指针类型
//HASH_ADD表示添加的键值可以是任意类型

//哈希表添加模板 int型
void HashAddItem_int(struct HashEntry_int **head, int key)
{
	struct HashEntry_int * temp;
    //申请节点空间
    temp = malloc(sizeof(struct HashEntry_int));
    //节点参数赋值
    temp->key = key;
    //添加到哈希表中
    HASH_ADD_INT(*head,key,temp);
}

//哈希表添加模板 字符串型
void HashAddItem_str(struct HashEntry_str **head, char *s)
{
    struct HashEntry_str * temp;
    //申请节点空间
    temp = malloc(sizeof(struct HashEntry_str));
    //节点参数赋值
    temp->key = malloc(sizeof(char)*(strlen(s)+1));
    strcpy(temp->key, s);
    //添加到哈希表中
    HASH_ADD_STR(*head, key, temp);
}

//哈希表添加模板 万能型 (long long 代替)
void HashAddItem_ll(struct HashEntry_ll **head, long long key)
{
	struct HashEntry_ll * temp;
    //申请节点空间
    temp = malloc(sizeof(struct HashEntry_ll));
    //节点参数赋值
    temp->key = key;
    //添加到哈希表中
    HASH_ADD(hh,*head,key,sizeof(long long),temp);
}

哈希表查找

// 哈希查找模板 int型
struct HashEntry_int* find_int(struct HashEntry_int **head, int key)
{
    struct HashEntry_int* temp = NULL;
    HASH_FIND_INT(*head, &key, temp);
    return temp;
}

struct HashEntry_str* find_str(struct HashEntry_str **head, char* s)
{
    struct HashEntry_str* temp = NULL;
    HASH_FIND_STR(*head, s, temp);
    return temp;
}

// 哈希查找模板 int型
struct HashEntry_ll* find_ll(struct HashEntry_ll **head, long long key)
{
    struct HashEntry_ll* temp = NULL;
    HASH_FINDl(hh, *head, &key, sizeof(long long) temp);
    return temp;
}

哈希表遍历

//哈希表遍历
// HASH_ITER(hh_name, head, item_ptr, tmp_item_ptr)
//两种通用
struct HashEntry *curr, *next;
HASH_ITER(hh, *obj, curr, next)
{
    //执行要做的操作      
}

//举例
//如删除
void hashFreeAll(struct HashEntry_str **head)
{
	struct HashEntry_str *cur, *next;
	HASH_ITER(hh, *head, cur, next){
    	//执行要做的操作 
        free(cur->key);
    	HASH_DEL(*head,cur);  
    	free(cur);
	}
}
void hashFreeAll(struct HashEntry_int **head)
{
	struct HashEntry_int *curr, *next;
	HASH_ITER(hh, *head, curr, next){
    	//执行要做的操作 
    	HASH_DEL(*head,curr);  
    	free(curr);
	}
}
void hashFreeAll(struct HashEntry_ll **head)
{
	struct HashEntry_ll *curr, *next;
	HASH_ITER(hh, *head, curr, next){
    	//执行要做的操作 
    	HASH_DEL(*head,curr);  
    	free(curr);
	}
}

其他函数详情请见下面链接

C语言哈希表uthash的使用方法详解(附下载链接)

二、实战模板使用

ps:(说明,题目可能有更好的解法,但是为了展示哈希表的使用,就使用hash表解题)

字符串模板

884. 两句话中的不常见单词

解题思路:

两句话中只出现一次的单词算不常见单词

所以只需要将两句话的单词分别加入哈希表中,并且统计该单词的出现次数,将次数为1的单进行输出

第一步、确定哈希结构
struct HashEntry{
  char *key; //字符串键值
  int times; //出现次数
  UT_hash_handle hh;
};
第二步、将字符串1和字符串2加入哈希表中

// 需要使用 查找和添加函数

自定义插入函数写逻辑 逻辑如下

对于一个字符串,先在哈希表中查找,如果找到了数量+1,没找到就加入哈希表中

第三步、遍历哈希表,将次数为1的字符串进行输出

代码部分(直接套模板):

#define MAX 200

struct HashEntry_str{
    char *key;
    int times;
    UT_hash_handle hh;
};

struct HashEntry_str* find_str(struct HashEntry_str **head, char* s)
{
    struct HashEntry_str* temp = NULL;
    HASH_FIND_STR(*head, s, temp);
    return temp;
}

//哈希表添加模板 字符串型
void HashAddItem_str(struct HashEntry_str **head, char *s)
{
    struct HashEntry_str * temp;
    //申请节点空间
    temp = malloc(sizeof(struct HashEntry_str));
    //节点参数赋值
    temp->times = 1;
    temp->key = malloc(sizeof(char)*(strlen(s)+1));
    strcpy(temp->key, s);
    //添加到哈希表中
    HASH_ADD_STR(*head, key, temp);
}

void insertHash(struct HashEntry_str **head, char *s)
{
    struct HashEntry_str * temp = NULL;
    temp = find_str(head,s);
    if(temp){
        temp->times++;
    }else{
        HashAddItem_str(head,s);
    }
}

void hashFreeAll(struct HashEntry_str **head)
{
	struct HashEntry_str *cur, *next;
	HASH_ITER(hh, *head, cur, next){
    	//执行要做的操作 
        free(cur->key);
    	HASH_DEL(*head,cur);  
    	free(cur);
	}
}

char ** uncommonFromSentences(char * s1, char * s2, int* returnSize){
    char **ans = malloc(sizeof(char*)*MAX);
    *returnSize = 0;
    struct HashEntry_str *head = NULL;
    //添加字符串到哈希表中
    char *c = strtok(s1," ");
    while(c != NULL){
        insertHash(&head,c);
        c = strtok(NULL, " ");
    }
    c = strtok(s2," ");
    while(c != NULL){
        insertHash(&head,c);
        c = strtok(NULL, " ");
    }

    //遍历哈希表
    struct HashEntry_str *cur,*next;
    HASH_ITER(hh,head,cur,next){
        if(cur->times == 1){
            ans[(*returnSize)] = malloc(sizeof(char)*(strlen(cur->key)+1));
            strcpy(ans[(*returnSize)++],cur->key);
        }
    }

    hashFreeAll(&head);
    return ans;
}

int值模板

1. 两数之和

解题思路:

先把数组中的元素加入到哈希表中,然后遍历数组,查找对应和为target的值,如果找到了就返回两个数值对应的下标

第一步、确认哈希结构
struct HashEntry_int {
    int key;                    /* key */
    int pos;					/* 下标 */
    UT_hash_handle hh;         /* makes this structure hashable */
};
第二步、在哈希表中查找相加等于target的值

​ 如果有值返回该值下标和当前下标

​ 如果没有值 将当前值和下标加入哈希表中

代码部分

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
struct HashEntry_int {
    int key;                    /* key */
    int pos;					/* 下标 */
    UT_hash_handle hh;         /* makes this structure hashable */
};

// 哈希表添加模板 int型
// 对添加函数稍微做了一些调整,多了一个参数
void HashAddItem_int(struct HashEntry_int **head, int key, int pos)
{
	struct HashEntry_int * temp;
    //申请节点空间
    temp = malloc(sizeof(struct HashEntry_int));
    //节点参数赋值
    temp->key = key;
    temp->pos = pos;
    //添加到哈希表中
    HASH_ADD_INT(*head,key,temp);
}

// 哈希查找模板 int型
struct HashEntry_int* find_int(struct HashEntry_int **head, int key)
{
    struct HashEntry_int* temp = NULL;
    HASH_FIND_INT(*head, &key, temp);
    return temp;
}


int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    int *ans = malloc(sizeof(int)*2);
    *returnSize = 0;
    struct HashEntry_int* head;
    struct HashEntry_int* temp = NULL;
    
    for(int i = 0; i < numsSize; i++){
        // 查找符合目标的值
        temp = find_int(&head,target-nums[i]);
        if(temp){
            // 找到了,赋值
            ans[0] = temp->pos;
            ans[1] = i;
            (*returnSize) = 2;
            break; 
        }else{
            // 没找到,把当前值加入哈希表中
            HashAddItem_int(&head,nums[i],i);
        }
    }
    return ans;
}

万能值模板

1001. 网格照明

解题思路
创建5个哈希表分别为
points 存储亮灯的点 --> key值为经过xy计算后的值
rows 存储亮灯的行 --> key值为所在行的值
cols 存储亮灯的列 --> key值为所在列的值
diagonal 存储亮灯的左上到右下\ --> key值为x-y 因为每一条斜线中的xy的差值相等
antiDiaginal 存储亮灯的右上到左下/ --> key值为x+y 因为每一条斜线中的xy的和值相等

先点灯,然后点亮该位置的灯之后,将其所能照亮的四条线路的亮度+1,如果有重复出现的,则不点灯。然后再对该位置周围的九个位置进行遍历,如果这些位置有灯,就灭掉,并且把这个灯所能照亮的区域的亮度-1 在遍历的过程中,如果该位置所处的四个区域任意一个位置亮度大于1,则该位置为1,否则为0;

第一步、确定哈希结构
typedef struct {
    long long key;
    int val;  // 用来存储亮度 有一个灯照亮为亮度1 两个灯照亮为亮度2
    UT_hash_handle hh;
} HashEntry;
第二步 点灯
// 把灯放进去
    for (int i = 0; i < lampsSize; i++) {
        // 避免多次列出时, 值重复累加, 已经加过的值就不再加入
        temp = FindHash(&points, ((long long)GetKey(lamps[i][0], lamps[i][1])));
        if (temp) {
            continue;
        }
        InsertHash(&points, (long long)GetKey(lamps[i][0], lamps[i][1]));
        InsertHash(&rows, (long long)lamps[i][0]);
        InsertHash(&cols, (long long)lamps[i][1]);
        InsertHash(&diagonal, (long long)(lamps[i][0] - lamps[i][1]));
        InsertHash(&antiDiaginal, (long long)(lamps[i][0] + lamps[i][1]));
    }
第三步 存放结果 第四步 关灯
for (int i = 0; i < queriesSize; i++) {
        if (IsLight(&rows, &cols, &diagonal, &antiDiaginal, queries[i][0], queries[i][1])) {
            ans[(*returnSize)++] = 1;
        } else {
            ans[(*returnSize)++] = 0;
        }

        // 关灯
        CloseLight(&points, &rows, &cols, &diagonal, &antiDiaginal, n, queries[i][0], queries[i][1]);
    }
第五步 返回结果
return ans;

代码部分


/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
/*
哈希表 创建五个哈希表
分别为 points 存储亮灯的点 rows 存储亮灯的行 cols 存储亮灯的列 diagonal 存储亮灯的左上到右下\ antiDiaginal 存储亮灯的右上到左下/
*/

typedef struct {
    long long key;
    int val;  // 用来存储亮度 有一个灯照亮为亮度1 两个灯照亮为亮度2
    UT_hash_handle hh;
} HashEntry;

long long GetKey(int x, int y)
{
    return (long long)x + ((long long)y << 32);
}

void AddHash(HashEntry **head, long long key)
{
    HashEntry *temp = NULL;
    temp = malloc(sizeof(HashEntry));
    temp->key = key;
    temp->val = 1;
    HASH_ADD(hh, *head, key, sizeof(long long), temp);
}

HashEntry *FindHash(HashEntry **head, long long key)
{
    HashEntry *temp = NULL;
    HASH_FIND(hh, *head, &key, sizeof(long long), temp);
    return temp;
}

void InsertHash(HashEntry **head, long long key)
{
    HashEntry *temp = NULL;
    temp = FindHash(head, key);
    if (temp) {
        temp->val++;
    } else {
        AddHash(head, key);
    }
}

void DelHash(HashEntry **head, long long key)
{
    HashEntry *temp = NULL;
    temp = FindHash(head, key);
    if (temp) {
        HASH_DEL(*head, temp);
        free(temp);
    }
}

void DivHash(HashEntry **head, long long key)
{
    HashEntry *temp = NULL;
    temp = FindHash(head, key);
    if (temp) {
        temp->val--;
    }
}

bool IsLight(HashEntry **rows, HashEntry **cols, HashEntry **diagonal, HashEntry **antiDiaginal, int x, int y)
{
    HashEntry *temp = NULL;
    temp = FindHash(rows, x);
    if (temp && temp->val > 0)
        return true;
    temp = FindHash(cols, y);
    if (temp && temp->val > 0)
        return true;
    temp = FindHash(diagonal, x - y);
    if (temp && temp->val > 0)
        return true;
    temp = FindHash(antiDiaginal, x + y);
    if (temp && temp->val > 0)
        return true;
    return false;
}

bool IsIngrid(int n, int x, int y)
{
    if (x >= 0 && x < n && y >= 0 && y < n) {
        return true;
    }
    return false;
}

void CloseLight(HashEntry **points, HashEntry **rows, HashEntry **cols, HashEntry **diagonal, HashEntry **antiDiaginal,
    int n, int x, int y)
{
    int range[9][2] = {{0, 0}, {0, 1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {1, -1}, {1, 0}, {1, 1}};
    for (int i = 0; i < 9; i++) {
        if (IsIngrid(n, x + range[i][0], y + range[i][1]) == false) {
            continue;
        }
        HashEntry *temp = NULL;
        temp = FindHash(points, GetKey(x + range[i][0], y + range[i][1]));
        if (temp == NULL)
            continue;
        DelHash(points, GetKey(x + range[i][0], y + range[i][1]));
        DivHash(rows, (long long)(x + range[i][0]));
        DivHash(cols, (long long)(y + range[i][1]));
        DivHash(diagonal, (long long)(x + range[i][0] - (y + range[i][1])));
        DivHash(antiDiaginal, (long long)(x + range[i][0] + y + range[i][1]));
    }
}

int *gridIllumination(int n, int **lamps, int lampsSize, int *lampsColSize, int **queries, int queriesSize,
    int *queriesColSize, int *returnSize)
{
    int *ans = malloc(queriesSize * sizeof(int));
    *returnSize = 0;
    HashEntry *points = NULL;
    HashEntry *rows = NULL, *cols = NULL;
    HashEntry *diagonal = NULL, *antiDiaginal = NULL;
    HashEntry *temp = NULL;
    // 把灯放进去
    for (int i = 0; i < lampsSize; i++) {
        // 避免多次列出时, 值重复累加, 已经加过的值就不再加入
        temp = FindHash(&points, ((long long)GetKey(lamps[i][0], lamps[i][1])));
        if (temp) {
            continue;
        }
        InsertHash(&points, (long long)GetKey(lamps[i][0], lamps[i][1]));
        InsertHash(&rows, (long long)lamps[i][0]);
        InsertHash(&cols, (long long)lamps[i][1]);
        InsertHash(&diagonal, (long long)(lamps[i][0] - lamps[i][1]));
        InsertHash(&antiDiaginal, (long long)(lamps[i][0] + lamps[i][1]));
    }

    for (int i = 0; i < queriesSize; i++) {
        if (IsLight(&rows, &cols, &diagonal, &antiDiaginal, queries[i][0], queries[i][1])) {
            ans[(*returnSize)++] = 1;
        } else {
            ans[(*returnSize)++] = 0;
        }

        // 关灯
        CloseLight(&points, &rows, &cols, &diagonal, &antiDiaginal, n, queries[i][0], queries[i][1]);
    }
    return ans;
}

相关题目链接

1. 两数之和

884. 两句话中的不常见单词

1001. 网格照明

-----后面做了其他题目会陆续增加相关内容

—2020.02.08更新 使用 long long 型参数当key值 更新 1001 题解

  • 3
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值