• 算法初步——散列


    散列的定义与整数散列

    • 题目要求:M个预查询的数中每个数在N个数中出现的次数
      • 思路:设定一个int型数组 hashTable[10010] ,然后在输入 N 个数时进行预处理,即当输入的数为 x 时 ,就令 hashTable[x]++,时间复杂度为 O(N+M)
        #include <cstdio>
        #include <string>
        #include <algorithm>
        #include <cmath>
        using namespace std;
        
        const int maxn = 100010;
        int hashTable[maxn] = {0};
        
        int main() {
            int n, m, x;
            scanf("%d%d", &n, &m);
            
            for(int i=0; i<n; ++i) {
                scanf("%d", x);
                hashTable[x]++;        // 记录每个数出现次数 
            }
            for(int i=0; i<m; ++i) {    // 输出 M 个数中每个数在 N 个数中出现的次数 
                scanf("%d", x);
                printf("%d
        ", hashTable[x]);
            } 
        
            return 0;
        }
    • 但是这个策略暂时还有一个问题——如果输入可能是10^9大小的整数,或者甚至是一个字符串,就不能将它们直接作为数组下标了,这时候可以使用散列,散列即 ” 将元素通过一个函数转换为整数,使得该整数可以尽量唯一的代表这个元素 “ ,常用的散列函数有 直接定址法、平方取中法、除留余数法等。
    • 除留余数法,H(key) = key % mod
    • 解决冲突的方法:线性探测法、平方探测法、链地址法

     

    字符串hash初步

    • 先假设字符串均由大写字母 A~Z 构成
      • 不妨把 A~Z 视为 0~25 ,这样就把26个大写字母对应到二十六进制中
      • 接着按照将二十六进制转换为十进制的思路,便可实现将字符串映射为整数的需求
        int hashFunc(char S[], int len) {    // hash 函数,将字符串 S 转换为整数 
            int id = 0;
            for(int i=0; i<len; ++i) {
                id = id*26 + (S[i]-'A');    // 将二十六进制转换为十进制 
            }
            
            return id;
        } 
    • 如果字符串中出现小写字母
      • 那么可以把 A~Z 视为 0~25 ,而把 a~z 视为 26~51 
      • 就变成了五十二进制转换为十进制的问题
        int hashFunc1(char S[], int len) {    // hash 函数,将字符串 S 转换为整数 
            int id = 0;
            for(int i=0; i<len; ++i) {
                if(S[i] >= 'A' && S[i] <= 'Z') {        // 大写字母 
                    id = id*52 + (S[i] -'A');
                } else if(S[i] >= 'a' && S[i] <= 'z') {    // 小写字母 
                    id = id*52 + (S[i] -'a') + 26;
                }
            }
            
            return id;
        } 
    • 而如果出现了数字,一般有两种处理方法:
      1. 按照小写字母的处理方法,增大进制数至62
      2. 如果保证在字符串的末尾是确定个数的数字,那么就可以把前面的英文字母的部分按上面的思路转换成整数,再将末尾的数字直接拼接上去。例如对由三个字符加一位数字组成的字符串 ”BCD4“ 来说,就可以先将前面的 ”BCD“ 转换为整数 731 ,然后直接拼接上末位4变为7314即可
        int hashFunc2(char S[], int len) {    // hash 函数,将字符串 S 转换为整数 
            int id = 0;
            for(int i=0; i<len-1; ++i) {
                id = id*26 + (S[i]-'A');    // 将二十六进制转换为十进制 
            }
            id = id*10 + (S[len-1] - '0');    // 拼接末位 
            
            return id;
        }
    • 以一个问题结尾:给出 N 个字符串(由恰好三位大写字母组成),再给出 M 个查询字符串,问每个查询字符串在N个字符串中出现的次数
      • 思路:将字符串转换为整数,然后利用上面的整数散列解决该问题
        #include <cstdio>
        #include <string>
        #include <algorithm>
        #include <cmath>
        using namespace std;
        
        const  int maxn = 100;
        char S[maxn][5], temp[5];
        int hashTable[26*26*26 + 10] = {0};
        
        int hashFunc(char S[], int len) {
            int id = 0;
            for(int i=0; i<len; ++i) {
                id = id*26 + (S[i]-'A');
            }
            
            return id;
        } 
        
        int main() {
            int n, m;
            scanf("%d%d", &n, &m);
            
            for(int i=0; i<n; ++i) {
                scanf("%s", S[i]);
                int id = hashFunc(S[i], 3);        // 将字符串转换为整数 
                hashTable[id]++;                // 该字符串出现次数+1 
            }
            for(int i=0; i<m; ++i) {
                scanf("%s", temp);
                int id = hashFunc(temp, 3);        // 将字符串 temp 转换为整数 
                printf("%d
        ", hashTable[id]);    // 输出该字符串出现次数 
            }
        
            return 0;
        }
  • 相关阅读:
    二分查找(通过相对位置判断区间位置)--17--二分--LeetCode33搜索旋转排序数组
    归并排序(归并排序求逆序对数)--16--归并排序--Leetcode面试题51.数组中的逆序对
    22-Java-Hibernate框架(二)
    21-Java-Hibernate框架(一)
    操作系统-5-进程管理(二)
    操作系统-4-进程管理(一)
    操作系统-3-操作系统引论
    操作系统-2-存储管理之LRU页面置换算法(LeetCode146)
    20-Java-正则表达式
    19-Java-核心类库2-包装类、Integer类、String类、StringBuffer类、StringBuilder类
  • 原文地址:https://www.cnblogs.com/coderJiebao/p/Algorithmofnotes04.html
Copyright © 2020-2023  润新知