您现在的位置是:首页 >技术杂谈 >代码训练营第6天网站首页技术杂谈
代码训练营第6天
主要是哈希表了
数组就是一张哈希表
什么时候考虑哈希法:当我们遇到要快速判断一个元素是否在集合里
哈希函数: 把学生姓名直接映射到集合上的索引
那么如果学生的数量大于哈希表的大小怎么办?
那么就是哈希碰撞:其实就是两个元素都映射到了同一位置
那么有两种解决方法:拉链法和线性探测法
拉链法:就是储存在链表里
线性探测法:首先一定要保证 你的哈希表的大小大于要放的数据 然后就是假设放满了,循环找到下一个空位去放元素
哈希结构:
那么如果你想用哈希法来解决问题的话,有以下几种哈希结构:
1 数组
2 set(集合)
3 map(映射)
首先数组没什么值得讨论的
那么c++中set有三种
1std::set 这种的底层实现是红黑树
红黑树就是一种自平衡的二叉树 那么这个树呢 有四个特点:
1 根结点是黑色
2 不能相邻两个结点是红色结点 也就是红色结点的叶子结点一定是黑色结点
3 最下面的结点一定是空的黑色叶子结点
4 每一个结点到其能到达的叶子结点的路径上都必须包含相同数量的黑色结点
因此这个set肯定是不能修改数据 因为你一修改就破坏平衡了 而且是有序的 你可以用中序遍历 时间复杂度是o(log2n)
那么其实红黑树是可以有相同元素的 其实std::set在实现的时候 先用了一个std::less的查找 确保没有相同元素再插入, 其他都和std::set一样 那么这两个肯定都是有序的 然后增删的效率都是O(log2n) 然后查找的效率也是O(log2n) 然后都不能更改数值
具体为什么是O(log n)呢 因为树是下一层是上一层的两倍,因此树的高度是log2n 因此你每次查找或者去增加 最多只是去遍历树的高度就行 因此最终的效率就是O(log下标2 n)。
那么还有一种结构是std::unordered_set 也就是哈希表, 底层实现是拉链法,首先肯定是无序的这个因为:哈希表的意义就是让元素均匀分配 你如果是想通过哈希函数来进行排序 那么就很有可能变成一个链表 那么哈希表就完全没意义了 因此你要想有序就直接用std::set来 红黑树更好 哈希表的优势就是随机访问 也就是增删和查询效率都为O(1)
另外 哈希表不能去更改元素的值 因为元素的位置是由其值的哈希决定的。因此,如果我们更改元素的值,就可能会改变它的哈希值,进而需要更改其在哈希表中的位置。 换句话说 你改元素的值 那么元素的哈希值就会改变 那么位置就会变 那么就乱了 因为没有重新定位的方法 所以你只能删了再增加
另外为什么没用重复元素呢 因为如果有重复元素就是一个格子去弄很多链表 也是一样的道理 那样效率就低很多了 所以哈希表一个是不能去有重复元素 一个是不能有顺序 一个是不能更改数值。
总结: 在做哈希表的题的时候 优先考虑std::unordered_set 如果是元素要求有序 那么再考虑std::set 如果元素有序又要重复 那么只能选择std::multiset 。 其实这两个的查询和增加删的效率都是O(log下标2n) 但哈希表的效率是O(1)
那么另外一个是hashmap:
hashmap和hashset的具体区别 那么等候捷的c++看完再说
题1 有效的字母异位词
其实还是很简单 但是一开始想的不对 一开始想的是去用multiset 但其实不是最优解 因为这个用数组就能搞定 所以一共有三种结构 数组 集合 和map 先想到的肯定是数组
注意来说 你在定义的时候 写的数组个数 就是从1开始数的 比如说 int[10] 就是10个数
class Solution {
public:
bool isAnagram(string s, string t) {
int a [26]={0};
for(int i=0;s[i]!='