哈希表的练习题解

在这里插入图片描述

今天的内容是哈希表

442. 数组中重复的数据

一道题四种解法,来自对于题解的理解。

暴力哈希表:直接看题目给出数据范围最大是10^5,直接开辟一个100001的数组当作哈希表来存储数字出现的次数。遍历即可。

int* findDuplicates(int* nums, int numsSize, int* returnSize){
    int hash[100001] = {0};
    *returnSize = 0;
    int* ans = (int*)malloc(sizeof(int)*numsSize);
    for(int i =0;i<numsSize;i++)
    {
        ++hash[nums[i]];
    }
    for(int i =0;i<100000;i++)
    {
        if(hash[i]==2)
        {
            ans[(*returnSize)++] = i;
        }
    }
    return ans;
}

思路2:原地修改数组,将原数组当作哈希表,然后遍历数组,每次将nums[abs(nums[i])-1]位置的值置为负数,如果,这个位置的值已经是负数了,说明之前出现过一次nums[i]了,那么这个数就出现了两次,直接将其放入结果数组。

int* findDuplicates(int* nums, int numsSize, int* returnSize){
    int* ans = (int*)malloc(sizeof(int)*numsSize);
    *returnSize = 0;

    for(int i =0;i<numsSize;i++)
    {
        if(nums[abs(nums[i])-1]>0)
        {
            nums[abs(nums[i])-1] = -nums[abs(nums[i])-1];
        }
        else
        {
            ans[(*returnSize)++] = abs(nums[i]);
        }
    }
    return ans;
}

思路3:交换数组元素到对的位置去,因为数组元素个数与元素大小是对应的,如果有元素出现两次,那么必有元素没有出现,直接将每个数组元素移动到对应的位置,最后遍历数组,如果nums[i]!=i+1,也即是该元素没有和位置对应,该元素就出现了两次。

int* findDuplicates(int* nums, int numsSize, int* returnSize){
    int*ans = (int*)malloc(sizeof(int)*numsSize);
    *returnSize = 0;
    for(int i =0;i<numsSize;i++)
    {
        while(nums[i]!=nums[nums[i]-1])//数字不在应该在的位置就交换
        {
            int tmp = nums[i];
            nums[i] = nums[tmp-1];
            nums[tmp-1] = tmp;
        }//每次交换都会将nums[i]放到对的位置,直到对的位置和要交换的数字对应了,说明该数字是第二次出现了,就跳出交换循环。
    }
    for(int i =0;i<numsSize;i++)
    {
        if(nums[i]!=i+1)
        {
            ans[(*returnSize)++] = nums[i];
        }
    }
    return ans;
}

思路4:原地哈希,遍历一边数组,将每个位置的而元素交换到正确的位置上,然后判断如果正确的位置上已经有了一个一样的元素,说明该元素是已经出现过的,就放入数组,同时将元素变为负数,防止该元素被交换到其他位置,被重复计入。

int* findDuplicates(int* nums, int numsSize, int* returnSize){
    int*ans = (int*)malloc(sizeof(int)*numsSize);
    *returnSize = 0;
    for(int i =0;i<numsSize;i++)
    {
        int t = nums[i];
        if(t < 0 || t == i+1)
            continue;
        if(nums[i] == nums[nums[i]-1])
        {
            ans[(*returnSize)++] = nums[i];
            nums[i] *=-1;
        }
        else//不相等则交换到正确的位置。同时此次遍历无效要让i--
        {
                int c = nums[t - 1];
                nums[t - 1] = t;
                nums[i--] = c;
        }
    }
    return ans;
}

2068. 检查两个字符串是否几乎相等

思路:哈希表记录两个数组中每个字符出现的次数,最后遍历两个哈希表求出差,大于3 false遍历结束,true。

bool checkAlmostEquivalent(char * word1, char * word2){
    int hash1[26] = { 0 };
    int hash2[26] = {0};

    for(int i =0;word1[i];i++)
    {
        int a = word1[i]-'a';
        ++hash1[a];
    }
    for(int i =0;word2[i];i++)
    {
        int a = word2[i]-'a';
        ++hash2[a];
    }
    for(int i =0;i<26;i++)
    {
        if(abs(hash1[i]-hash2[i])>3)
        {
            return false;
        }
    }
    return true;
}

2283. 判断一个数的数字计数是否等于数位的值

思路: 10个元素的哈希表记录每个元素出现的次数,然后哦遍历,哈希表,最大下标是数组长度,然后将数组内容对应成数字就是该下标数字出现的次数count,然后与哈希表记录的次数比较,不同就返回false。

bool digitCount(char * num){
    int hash[10] = {0};
    int len = strlen(num);
    for(int i =0;num[i];i++)
    {
        int a = num[i] - '0';
        ++hash[a];
    }

    for(int i =0;i<len;i++)
    {
        int count = num[i] -'0';
        if(count!=hash[i])
        return false;
    }
    return true;
}

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

官方题解,日后重刷
思路:利用字符串作为哈希表的索引,先将字符串分割然后加入哈希表中,最后遍历哈希表,如果有单词出现了一次,就把它加入结果数组。
关于c语言使用哈希表的链接学习。

typedef struct  {
    char * word;            
    int val;
    UT_hash_handle hh;
} HashEntry;

bool insert(char * str, HashEntry ** obj) {
    HashEntry * pEntry = NULL;
    char *token = NULL;

    token = strtok(str, " ");
    while (token != NULL ) {
        pEntry = NULL;
        HASH_FIND_STR(*obj, token, pEntry);
        if (NULL == pEntry) {
            HashEntry * pEntry = (HashEntry *)malloc(sizeof(HashEntry));
            pEntry->word = (char *)malloc(sizeof(char) * (strlen(token) + 1));
            strcpy(pEntry->word, token);
            pEntry->val = 1;
            HASH_ADD_STR(*obj, word, pEntry);
        } else {
            pEntry->val++;
        }
        token = strtok(NULL, " ");
    }
    return true;
}

char ** uncommonFromSentences(char * s1, char * s2, int* returnSize){
    HashEntry * freq = NULL;
    HashEntry * pEntry = NULL;

    insert(s1, &freq);
    insert(s2, &freq);
    unsigned int sentenceSize = HASH_COUNT(freq);
    char ** ans = (char **)malloc(sizeof(char *) * sentenceSize);
    int pos = 0;
    HashEntry *curr = NULL, *next = NULL;
    HASH_ITER(hh, freq, curr, next) {
        if (curr->val == 1) {
            ans[pos] = (char *)malloc(sizeof(char) * (strlen(curr->word) + 1));
            strcpy(ans[pos], curr->word);
            pos++;
        }
    }
    HASH_ITER(hh, freq, curr, next) {
        free(curr->word);
        HASH_DEL(freq, curr);
    }
    *returnSize = pos;
    return ans;
}

补充

1512. 好数对的数目

思路:先根据题目实例分析,数据范围是1–100可以用哈希表记下数字出现次数。遍历数组,如果去哈希表中查找,之前出现过没有,出现过就将出现次数加到计数器上,然后自增哈希表对应位置的次数。

int numIdenticalPairs(int* nums, int numsSize){
    int hash[101] = {0};
    int ans = 0;
    for(int i =0;i<numsSize;i++)
    {
        if(hash[nums[i]])
            ans+=hash[nums[i]];
        ++hash[nums[i]];
    }
    return ans;
}

2006. 差的绝对值为 K 的数对数目

思路1:暴力出奇迹,没有什么是两个for循环不能解决的,如果有,那就再来一个。

int countKDifference(int* nums, int numsSize, int k){
    int cnt = 0;
    for(int i = 0;i<numsSize;i++)
    {
        for(int j = i+1;j<numsSize;j++)
        {
            if(abs(nums[i]-nums[j])==k)
            {
                cnt++;
            }
        }
    }
    return cnt;
}

思路2:哈希表,可以看出nums[i] = k+nums[j] 或者 -k+nums[j];所以这就给我们一个哈希思路,遍历数组去哈希表里面查找哈希表中是否存在nums[i]也即是k±nums[j],出现一个就是一个满足的数组,加到计数器上就可。
要注意判断nums[i]±k是不是在数组范围内,防止越界。

int countKDifference(int* nums, int numsSize, int k){
    int cnt = 0;
    int hash[101] = {0};
    for(int i =0;i<numsSize;i++)
    {
        if(nums[i]+k>0 && nums[i]+k<=100)
            cnt+=hash[nums[i]+k];
        if(nums[i]-k>0 && nums[i]-k<=100)
            cnt+=hash[nums[i]-k];
        ++hash[nums[i]];
    }
    return cnt;
}

1347. 制造字母异位词的最小步骤数

思路:定义一个哈希表,记录字符串s中出现的字符个数,然后枚举t中的字符个数,用s的每个字符个数减掉t中出现的字符的个数,如果结果为负,则说明该字符只在t中出现过,不用管,如果为0,则说明这个字符两个字符串都有,所以不用换,只有哈希表中大于0的字符,说明s中有t中没有,所以就需要把这些字符替换进t中,代替那些在hashs中<0的字符。

int minSteps(char * s, char * t){
    int hashs[26] = {0};
    int cnt = 0;
    for(int i =0;s[i];i++)
    {
        ++hashs[s[i]-'a'];
    }
    for(int i =0;t[i];i++)
    {
        --hashs[t[i]-'a'];
    }
    for(int i =0;i<26;i++)
    {
        if(hashs[i]>0)
            cnt+=hashs[i];
    }
    return cnt;
}

放个没解决的链接。
https://leetcode.cn/problems/group-anagrams-lcci/

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KissKernel

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值