关于hash的一些题目

90 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 20 天,点击查看活动详情

哈希表

哈希表是一种特殊数据结构。他可以通过某种函数,让原神存储位置和他的关键码可以建立一一映射的关系。

在hash里面常提到哈希冲突,其实就是通过哈希函数计算出的位置相同,但是一个地方只能存储一个数,所以需要另外处理。

  • 处理办法1;开发定址法

其实就是从当前位置开始向后遍历,找到后面第一个为null的地方,插入一个冲突数。

image.png

那么你可能会问,如果我把数插入到其他位置那么如果下载值是需要插入某位置,但是在他之前,因为hash冲突我们移动了另外一个值,是不是会再次冲突?是的,所以我们继续上面冲突解决操作。

  • 链地址法

在发生冲突时候,把数据遍历链表,连接在位置后面。

image.png

但是如果一直连接下去,可能会导致某条链表非常长,同样不利于我们查询,所以引入了B+树等。

怎么求两数的和?

给出一个整型数组 numbers 和一个目标值 target,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列。

最直接的办法就是循环遍历数组,找到值后给数组赋值,然后返回值

image.png

但是这样在数据非常大的时候,会出现超时情况,所以不能直接就这样提交。我们可以这样想。

如果我们做一个结构,可以存储值和下标,那么就能一次循环拿到结构了,所以本题我们可以考虑hashmap。如果哈希表里面包括了目标值-当前数的查找,那么表示找到了一个结构,进行赋值返回。

image.png

三数之和

给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。

可以复制两个数组,一个内层做两数和,一个外层做遍历。

image.png

上面数组一个指针,从左到右遍历,下面一个双指针开始遍历,left=上面数组指针+1,right=num.length-1

这种情况下,需要先进行排序,这样数组有序才能做。

排序方法省略。

然后进行上面循环,因为下面左指针比他大1,所以他最大应该是num.length-2

image.png

出现次数超过一半的数字。

给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

这个题很明显就是考虑hash了,声明hashmap,如果里面有当前值,value++,否则加入当前数字

image.png

出现次数只有一次的两个数

一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

这个题我们可以使用位运算做,因为 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

image.png

不过本题的常规做法还是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,加入完成后,重新遍历哈希表,找到第一个没有出现的正整数

image.png