【算法集训】基础数据结构:十三、哈希表

今天是基础数据结构的最后一个。至此我们的基础数据结构系列就结束了!!!
这几天先告一段落,等期末考试完继续更新算法系列。


哈希表又叫散列表,通常用数组来实现,又叫做哈希数组。

一、概念

常用哈希函数

1、直接定址法;
关键字本身就是哈希值,例如f(x) = x;
2、平方取中法
3、折叠法
4、除留取余法(常用)
f(x) = x % m
5、位与法

哈希冲突解决方法

1、开放定址法
如果发生冲突则寻找下一个空地址。
2、链地址法
发生冲突后不换地址,使用链表将链接到当前的值的后面

第一题 41. 缺失的第一个正数

int hash[500002]; //定义哈希数组

int firstMissingPositive(int* nums, int numsSize) {
    memset(hash, 0, sizeof(hash));  //初始化为0
    // 遍历数组,传入哈希
    for(int i = 0; i < numsSize; ++i) {
        int v = nums[i];
        //如果值负数或大于500000,那后面就不用看了,因为数组长度只有500000,里面必定有空值。
        if(nums[i] <= 0 || nums[i] > 500000) {
            continue;
        }
        hash[ v ] = 1;
    }
    for(int i = 1; ; ++i) {
        if(!hash[i]) {
            return i;
        }
    }
    return -1;
}

第二题 387. 字符串中的第一个唯一字符

int firstUniqChar(char* s) {
    int hash[26];
    memset(hash, 0, sizeof(hash));
    //遍历数组的方法;如果出现一次字符则+1
    for(int i = 0; s[i]; ++i) {
        hash[s[i] - 'a']++;
    }
    // 遍历数组判断当前对应的哈希表是否为1,返回索引值即可
    for(int i = 0; s[i]; ++i) {
        if(hash[s[i] - 'a'] == 1) {
            return i;
        }
    }
    return -1;
}

第三题 215. 数组中的第K个最大元素

#define BASE 10000
int hash[2 * BASE + 5];

int findKthLargest(int* nums, int numsSize, int k) {
    memset(hash, 0, sizeof(hash));

    for(int i = 0; i < numsSize; ++i) {
        int index = nums[i] + BASE;
        hash[index]++;
    }
    
    for(int i = 2 * BASE; i >= 0; --i) {
        while( hash[i] ) {
            k--;
            hash[i]--;
            if( k == 0 ) {
                return i - BASE;
            }
        }
    }
    return -1;
}

第四题 1. 两数之和

hash[i]代表数字i + hash[i] == target;

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
//实现哈希表
#define BIT 16 //定义16位,我也不知道什么意思
#define MASK ((1 << BIT) - 1) //说是掩码,就是2^16 - 1 = 65535
#define MAGIC 1000000001  //定义一个边界,用于初始化哈希表
int hash[MASK + 1]; //创建哈希表

//初始化哈希表
void HashInit() {
    //里面的值都赋值为取不到的值,表示为空
    for(int i = 0; i <= MASK; ++i) {
        hash[i] = MAGIC;
    }
}

int HashFindAndInsert( int x ) {
    int v = x & MASK; //于操作,等于将x变为正数,如果不是负数则就是x
    while(1) {
        //如果当前哈希数组为空则插入
        if(hash[v] == MAGIC) {
            hash[v] = x;
            return v;
        }else if(hash[v] == x) { //如果是x表明已经插入了,直接返回
            return v;
        }
        v = (v + 1) * MASK;  //如果不满足要求,v往前移动一位,直到满足要求
    }
}


int pos[MASK + 1];
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
    int *ret = (int *)malloc(sizeof(int) * 2);
    *returnSize = 2;
    HashInit();
    memset(pos, -1, sizeof(pos));

    for(int i = 0; i < numsSize; ++i) {
        int idx = HashFindAndInsert(target - nums[i]);  //得到target - b = a里面的a
        if(pos[idx] != -1) {
            ret[0] = pos[idx];
            ret[1] = i;
            return ret;
        }
        //
        pos[ HashFindAndInsert(nums[i]) ] = i;
    }
    *returnSize = 0;
    return ret;
}

你可能感兴趣的:(【算法集训】基础数据结构,数据结构,算法,散列表)