当前位置: 首页 > article >正文

codetop哈希表刷题!!!刷穿地心版)

codetop标签哈希表+近半年,包含代码随想录,持续补充

  • 1.H指数
  • 2.有效的字母异位词
  • 3.快乐数
  • 4.赎金信
  • 5.前k个高频元素
  • 6.O(1)时间插入、删除和获取随机元素
  • 7.TinyURL的加密与解密

1.H指数

给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数。

根据维基百科上 h 指数的定义:h 代表“高引用次数” ,一名科研人员的 h 指数 是指他(她)至少发表了 h 篇论文,并且 至少 有 h 篇论文被引用次数大于等于 h 。如果 h 有多种可能的值,h 指数 是其中最大的那个。

分析一下,核心:至少有h篇论文的引用次数都大于或等于h
首先,排序,h逐步加大,不用管加大之后,前面遍历的cite还合不合法,因为是从大到小排序的,如果后面遍历到的数字都满足>h,那么前面的一定大于h

其中if (citations[i] >= h + 1)非常关键,使用 h + 1 是因为我们正在检查是否可以将 h 增加 1,也就是说,当前引用次数必须至少满足 h + 1 才能使 h 增加。

class Solution {
public:
    int hIndex(std::vector<int>& citations) {
        sort(citations.begin(), citations.end(), greater<int>()); // 从大到小排序
        int h = 0;
        
        for (int i = 0; i < citations.size(); ++i) {
            if (citations[i] >= h + 1) { // 检查是否满足 h 指数条件
                h++;
            } else {
                break; // 如果不满足条件,直接结束
            }
        }
        
        return h; // 返回最终的 h 指数
    }
};

2.有效的字母异位词

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

示例 1: 输入: s = “anagram”, t = “nagaram” 输出: true

示例 2: 输入: s = “rat”, t = “car” 输出: false

说实话,滑动窗口也能解决,但是有点大刀砍苍蝇了…
放在这篇blog,是用哈希来解决的
数组其实就是个简单的哈希表,而且这题里面只有小写字符,那么就可以定义一个组,来记录字符串s里的字符出现的次数。

class Solution {
public:
    bool isAnagram(string s, string t) {
        if(s == t) return false;
        int record[26] = {0};
        for(int i = 0; i < s.size(); i ++){
            record[s[i] - 'a'] ++;
        }
        for(int i = 0; i < t.size(); i ++){
            record[t[i] - 'a'] --;
        }
        for(int i = 0; i < 26; i ++){
            if(record[i] != 0) return false;
        }
        return true;
    }
};

3.快乐数

编写一个算法来判断一个数是不是快乐数:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果无法true,那么一定会陷入死循环!以此为入口
先写一个函数,用来取出各个位上的单数之和

int getSum(int n){
	int sum = 0;
	while(n){
		sum += (n % 10) * (n % 10);
		n = n / 10;
	}
	return sum;
}

isHappy函数:

bool isHappy(int n){
	unordered_set<int> set;
	while(1){
		int sum = getSum(n);
		if(sum == 1) return true;
		if(set.find(sum) != set.end()){
			return false;
		}else{
			set.insert(sum);
		}
		n = sum;
	}
};

4.赎金信

给你两个字符串:ransomNote 和 magazine ,判断
给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串 ransom 能不能由第二个字符串 magazines 里面的字符构成。如果可以构成,返回 true ;否则返回 false。

magazine 中的每个字符只能在 ransomNote 中使用一次。

有效字符串要的是相互组成,这个是a能否由b组成
因为题目说只有小写字母,那可以采用空间换取时间的哈希策略,用一个长度为26的数组来记录magazine里字母出现的次数。
不用随便用map,数据量散的话用map是不划算的!

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int record[26] = {0};
        if(ransomNote.size() > magazine.size()) return false;
        for(int i = 0; i < magazine.size(); i ++) record[magazine[i] - 'a']++;
        for(int i = 0; i < ransomNote.size(); i ++){
            record[ransomNote[i] - 'a'] --;
            if(record[ransomNote[i] - 'a'] < 0) return false;
        }
        return true;
    }
};

5.前k个高频元素

返回频率最高的,任意顺序

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> valTohz;
        for(int i = 0; i < nums.size(); i ++){
            valTohz[nums[i]]++;
        }
        vector<pair<int, int>> vec(valTohz.begin(), valTohz.end());
        sort(vec.begin(), vec.end(), [](pair<int, int> a, pair<int, int> b){return a.second > b.second;});

        vector<int> res;
        for(int i = 0; i < k; i ++){
            res.push_back(vec[i].first);
        }
        return res;

    }
};

6.O(1)时间插入、删除和获取随机元素

实现一个RandomizedSet类:

  • RandomizedSet() 初始化 RandomizedSet 对象
  • bool insert(int val) 当元素 val 不存在时,向集合中插入该项,并返回 true ;否则,返回 false 。
  • bool remove(int val) 当元素 val 存在时,从集合中移除该项,并返回 true ;否则,返回 false 。
  • int getRandom() 随机返回现有集合中的一项(测试用例保证调用此方法时集合中至少存在一个元素)。每个元素应该有 相同的概率 被返回。

你必须实现类的所有函数,并满足每个函数的 平均 时间复杂度为 O(1) 。

思路:
对于一个HashSet,无法在O(1)时间内实现getRandom函数。因为元素是被哈希函数分散到整个数组里面的,基本做不到O(1)时间等概率。
换句话说,对于 getRandom 方法,如果想「等概率」且「在 O(1) 的时间」取出元素,一定要满足:

  • 底层用数组实现,且数组必须是紧凑的,这样我们就可以直接生成随机数作为索引,选取随机元素。
  • 但如果用数组存储元素的话,常规的插入,删除的时间复杂度又不可能是 O(1)。然而,对数组尾部进行插入和删除操作不会涉及数据搬移,时间复杂度是 O(1)。

解决:
底层用数组实现,元素的排列必须紧凑,另外,删除元素的时候,用尾部元素与其交换,删除尾部元素,利用pop

class RandomizedSet {
public:
	vector<int> nums;//记录元素
	unordered_map<int, int> valToIndex;//记录每个元素对应的索引
    RandomizedSet() {

    }
    
    bool insert(int val) {
    	//如果val已经存在,那么就不用再插入了
    	if(valToIndex.count(val)) return false;
    	//如果val不存在
    	valToIndex[val] = nums.size();
    	nums.push_back(val);//插到尾部O(1)
    	return true;
    }
    
    bool remove(int val) {
    	//如果val不存在,那么就不用再移除了
    	if(!valToIndex.count(val)) return false;
    	//如果val存在
    	int index = valToIndex[val];
    	swap(nums[index], nums[nums.size() - 1]);
    	valToIndex[nums[index]] = index;//换到前面的尾部元素更新索引
    	nums.pop_back();//移除出nums
    	valToIndex.erase(val);//移除出索引
    	return true;
    }
    
    int getRandom() {
    	return nums[rand() % nums.size()];
    }
};

7.TinyURL的加密与解密

输入一个网址,想办法设计一个加密算法encode和一个解密算法decode,使输入一个网址,这一串完整经过加密和解密之后输出原网址

使用异或^来解决,将字母和数字进行异或操作是常见的,尤其是在执行简单的加密或编码任务时。字母和其他字符在底层都是以整数形式存储的,通常是 ASCII 码的形式。这意味着每个字符都对应一个整数值,因此可以直接与其他整数进行二进制运算。
编码和解码都和相同的值异或就行。

class Solution {
public:
    // Encodes a URL to a shortened URL.
    string encode(string longUrl) {
        int len = longUrl.size();
        for(int i = 0; i < len; i ++){
            longUrl[i] ^= 1;
        }
        return longUrl;        
    }

    // Decodes a shortened URL to its original URL.
    string decode(string shortUrl) {
        for(int i = 0; i < shortUrl.size(); i ++){
            shortUrl[i] ^= 1;
        }
        return shortUrl;        
    }
};


http://www.kler.cn/a/311414.html

相关文章:

  • 稀疏视角CBCT重建的几何感知衰减学习|文献速递-基于深度学习的病灶分割与数据超分辨率
  • 【机器学习】机器学习中用到的高等数学知识-3.微积分 (Calculus)
  • Docker网络和overlay的基础讲解
  • uni-app表单⑪
  • Django 详细入门介绍
  • srs http-flv处理过程
  • 如何使用ssm实现基于web的物流配送管理系统的设计与实现+vue
  • 【TabBar嵌套Navigation案例-关于页面 Objective-C语言】
  • FlexNet Licensing: not running 问题
  • IBM中国研发中心撤离背后的IT行业人才挑战与产业未来展望
  • web - JavaScript
  • .env文件详解(vite项目全局配置文件)
  • langchain报错记录(js)
  • node+express部署多套vue3项目,总404页面由node控制,子404页面由子vue控制,node路由重定向
  • 力扣 42.接雨水
  • MacOS Catalina 从源码构建Qt6.2开发库之01: 编译Qt6.2源代码
  • 机器学习-监督学习:朴素贝叶斯分类器
  • [C语言]第九节 函数一基础知识到高级技巧的全景探索
  • Python基础(九)——正则表达式
  • 软件工程中的耦合:类型、影响与优化策略
  • 索引的介绍
  • 【数据结构-差分】【hard】力扣995. K 连续位的最小翻转次数
  • 【RabbitMQ】重试机制、TTL
  • hku-mars雷达相机时间同步方案-软件驱动(MID360与海康MV-CB060-10UMUC-S)
  • 2-99 基于matlab多尺度形态学提取眼前节组织
  • 3 种自然语言处理(NLP)技术:RNN、Transformers、BERT