九日集训第七日(哈希表)

九日算法C++

    没有之前的,懒



前言

2022の夏天,半壶水响叮当的我决定充实一下自我


一、内容介绍

学校老师:key——value,一一对应

unordered_map<char,int> hash;
hash.insert(pair<char,int>('A', 10));

插入(insert)问题:哈希冲突,不能一一对应,则扩容,换划分规则
查找(find):找key,找不到返回.end(),冲突查找:给他来个桶,线性或指数增长查找


使用:不用你考虑冲突,一一对应双射函数就行,可理解为2*n无index矩阵,例:电话簿

二、练习题目(来自力扣)

项目完成情况
面试题 17.05. 字母与数字
970. 强整数
914. 卡牌分组
1497. 检查数组对是否可以被 k 整除

三、代码思路

1.面试题 17.05. 字母与数字

思想:转哈希表为一对一势能(最小等势能)
    (1)与原数组index一一对应,做势能数组(??)
    (2)找等势能点 l =势能+1 到 r =i,中长度最长len

class Solution {
public:
    vector<string> findLongestSubarray(vector<string>& array) {
        int sum[100010];
        int i;
        int pre =0;
        for(i =0;i <array.size(); ++i){
            sum[i] =pre;//上一个
            if(array[i][0] >='0' && array[i][0] <='9'){//是数 +1
                sum[i] +=1;
            }else {
                sum[i] -=1;
            }
            pre =sum[i];// 记录长
        }

        //窗口l,r
        unordered_map<int, int> hash;
        hash[0] = -1; //hash[最小等势能] ==位置,记录未开始为0势能
        int l =0,r =-1,maxlen =0;
        for(i =0;i <array.size(); ++i){
            if(hash.find(sum[i]) !=hash.end()) {//找到
                int len =i -hash[sum[i]];//窗口长
                if(len >maxlen){
                    maxlen =len;
                    l =hash[sum[i]] +1;
                    r =i;//
                }
            }
            else hash[ sum[i] ] =i;// 无, 则覆盖
        }
        vector<string> ret;
        for(i =l;i <=r; ++i){
            ret.push_back( array[i] );
        }
        return ret;
    }
};

2.970. 强整数

思想:一维数组条件遍历
    (1)先缓存x,y的幂积,到xs,ys,注意底数为1
    (2)遍历

class Solution {
public:
    vector<int> powerfulIntegers(int x, int y, int bound) {
        vector<int> xs, ys;
        int i,j;
        int prex =1, prey =1;
        for(i =1; prex <= bound; ++i){
            xs.push_back(prex);
            prex *=x;
            if(x ==1) {
                break;
            }
        }
        for(i =1; prey <= bound; ++i){
            ys.push_back(prey);
            prey *=y;
            if(y ==1) {
                break;
            }
        }
        
        unordered_set<int> ret;
        for(i =0;i <xs.size(); ++i){
            for(j =0;j <ys.size(); ++j){
                int val =xs[i] + ys[j];
                if(val <= bound){
                    ret.insert(val);
                }
            }
        }
        return vector<int>(ret.begin(), ret.end());
    }
};

3.914. 卡牌分组

思想:等价划分
    (1)gcd,最小公约数,辗转相除法,迭代函数,牛逼
    (2)hash:key:deck某数——value:某数出现次数
    (3)一组卡:1X4,2X2,故找到出现次数最小公约数totgcd

class Solution {
    int gcd(int a, int b){//最大公约数,辗转相除k
        return !b? a: gcd(b , a%b);//b=0 return a
    }
public:
    bool hasGroupsSizeX(vector<int>& deck) {
        int hash[10010];
        int n =deck.size();
        int max_num =-1;
        memset(hash , 0 ,sizeof(hash));//初始化哈希表为0
        for(int i =0; i <n; ++i){
            ++hash[ deck[i] ];//对于deck[i]分割,映射为出现次数
            max_num = max(max_num , deck[i]);//hash范围
        }
        
        int totgcd =-1;
        for(int i =0; i <=max_num; ++i){
            if(hash[i]){//有出现次数
                if(totgcd == -1){
                    totgcd = hash[i];
                }else {
                    totgcd = gcd(totgcd , hash[i]);
                }
                if(totgcd ==1) return false;
            }
        }
        return true;//最大公约数不为1
    }
};

4.1497. 检查数组对是否可以被 k 整除

思想:等价划分(分块)
    (1)转哈希表:key:余数——value:等价类个数
    (2)ik-i余数的个数相同,且0整除树为偶数

class Solution {
public:
    bool canArrange(vector<int>& arr, int k) {
        int n =arr.size();
        int hash[k +1];
        memset(hash , 0 , sizeof(hash));
        for(int i =0; i <n; ++i){
            int mod =(arr[i]%k +k) %k;//防止负数
            ++hash[ mod ];
        }
        if(hash[0] & 1) return false;//取第一位,等价除余2
        for(int i =1;i <k; ++i){
            if(hash[i] != hash[k-i]){
                return false;
            }
            if(i > (k/2 +1)){
                return true;
            }
        }
        return true;
    }
};

晚安玛卡巴卡

跟刷题大佬(B站英雄在哪里),早上五点等你

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值