开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 20 天,点击查看活动详情
哈希表
哈希表是一种特殊数据结构。他可以通过某种函数,让原神存储位置和他的关键码可以建立一一映射的关系。
在hash里面常提到哈希冲突,其实就是通过哈希函数计算出的位置相同,但是一个地方只能存储一个数,所以需要另外处理。
- 处理办法1;开发定址法
其实就是从当前位置开始向后遍历,找到后面第一个为null的地方,插入一个冲突数。
那么你可能会问,如果我把数插入到其他位置那么如果下载值是需要插入某位置,但是在他之前,因为hash冲突我们移动了另外一个值,是不是会再次冲突?是的,所以我们继续上面冲突解决操作。
- 链地址法
在发生冲突时候,把数据遍历链表,连接在位置后面。
但是如果一直连接下去,可能会导致某条链表非常长,同样不利于我们查询,所以引入了B+树等。
怎么求两数的和?
给出一个整型数组 numbers 和一个目标值 target,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列。
最直接的办法就是循环遍历数组,找到值后给数组赋值,然后返回值
但是这样在数据非常大的时候,会出现超时情况,所以不能直接就这样提交。我们可以这样想。
如果我们做一个结构,可以存储值和下标,那么就能一次循环拿到结构了,所以本题我们可以考虑hashmap。如果哈希表里面包括了目标值-当前数的查找,那么表示找到了一个结构,进行赋值返回。
三数之和
给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。
可以复制两个数组,一个内层做两数和,一个外层做遍历。
上面数组一个指针,从左到右遍历,下面一个双指针开始遍历,left=上面数组指针+1,right=num.length-1
这种情况下,需要先进行排序,这样数组有序才能做。
排序方法省略。
然后进行上面循环,因为下面左指针比他大1,所以他最大应该是num.length-2
出现次数超过一半的数字。
给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
这个题很明显就是考虑hash了,声明hashmap,如果里面有当前值,value++,否则加入当前数字
出现次数只有一次的两个数
一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
这个题我们可以使用位运算做,因为 1异或1=0,1异或0=1,0异或0=1.
所以如果只需要查找有关数,把数字值进行异或,最好剩下的就是不同的数。
int res=0 for(int cur:数组) res^=cur
最后res就是那个奇次出现的
但是现在说要两个数
如果数组存在两个数奇次出现,其他偶次出现
总体异或,发现不为0,那么res=a^b
那么必然 结果二进制有一个是1 取出最右侧1 res^(~res+1) 准备一个变量r 对数组遍历,如果数组值和变量 与运算 结果为1,那么变量等于自己和当前值异或 那么得到结果 r=a,res^r=b
不过本题的常规做法还是hash表
思路如下:创建一个哈希表当数组元素没有在哈希表中成为key的时候,put进哈希表,当已存在的时候,则remove掉。最后哈希表中剩下的key就是只出现一次的数字 遍历key然后返回结果
public int[] FindNumsAppearOnce (int[] array) {
// write code here
// 用于返回结果
int[] res = new int[2];
// 创建一个哈希表
HashMap<Integer,Object> set = new HashMap<>();
for(int i = 0; i < array.length; i++){
// 如果已经被当作key了,那就直接remove掉
if(set.containsKey(array[i])){
set.remove(array[i],null);
}else{
// 否则就添加进去
set.put(array[i],null);
}
}
int i = 0;
// 最后拿出来放进返回结果的数组中进行返回
for(Integer num:set.keySet()){
res[i++] = num;
}
return res;
}
寻找缺失的第一个正整数。
思路:把数组遍历加入hashmap,加入完成后,重新遍历哈希表,找到第一个没有出现的正整数