【面试必刷101】哈希

摘要

【面试必刷101】系列blog目的在于总结面试必刷101中有意思、可能在面试中会被考到的习题。总结通用性的解题方法,针对特殊的习题总结思路。既是写给自己复习使用,也希望与大家交流。

【面试必刷101】递归/回溯算法总结I
【面试必刷101】递归/回溯算法总结II
【面试必刷101】链表
【面试必刷101】二叉树
【面试必刷101】二分查找
【面试必刷101】栈和队列

1 基础知识

Hash,一般翻译做“散列”,也有直接音译为"哈希"的,就是把任意长度的输入(又叫做预映射, pre-p_w_picpath), 通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相 同的输出,而不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。总之,hash是指用一小段数据 来标识容量很大的一段数据,以验证它的完整性。

只需要记住,根据hash值取数,其时间复杂度为O(1),但是空间复杂度为O(n)。

2 面试必刷习题

2.1 数组中只出现一次的两个数字

在这里插入图片描述
这里就不画蛇添足了,看看这个老哥的题解:
题解 | #数组中只出现一次的两个数字#_牛客博客 (nowcoder.net)

import java.util.*;

public class Solution {
    public int[] FindNumsAppearOnce (int[] array) {
        // 先全部求异或操作
        int t = 0;
        for (int i = 0; i < array.length; i++) {
            t ^= array[i];
        }
        // 找到不同的位数
        int idx = 1;
        while ((t & idx) == 0) {
            idx <<= 1;
        }
        // 按照cnt来进行分组
        int t1 = 0, t2 = 0;
        for (int i = 0; i < array.length; i++) {
            if ((array[i] & idx) == 0) {
                t1 ^= array[i];
            } else {
                t2 ^= array[i];
            }
        }
        if (t1 > t2) {
            int tmp = t1;
            t1 = t2;
            t2 = tmp;
        }
        return new int[]{t1, t2};
    }
}

2.2 数组中出现次数超过一半的数字

在这里插入图片描述
投票算法:很好了理解,数量超过一半。谁来都不好使,我要一个人打你们全部人,反正我数量还是超的,最后剩下的一定是我。

import java.util.*;
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        // 空间复杂度为O(1)表示不能使用hashmap呀?
        // 数组长度超过一半的特点是啥? 采用“投票算法Boyer-Moore”
        int condinate = array[0];
        int cnt = 0;
        for (int i = 0; i < array.length; i++) {
            if (array[i] == condinate) {
                cnt ++;
            } else {
                cnt --;
            }
            if (cnt == 0) {
                condinate = array[i + 1];
            }
        }
        return condinate;
    }
}

2.3 缺失的第一个正整数

原地hash,利用正负值作为判别出没有出现过
在这里插入图片描述

step 1:我们可以先遍历数组将所有的负数都修改成n+1。
step 2:然后再遍历数组,每当遇到一个元素绝对值不超过n时,则表示这个元素是1~n中出现的元素,我们可以将这个数值对应的下标里的元素改成负数,相当于每个出现过的正整数,我们把与它值相等的下标都指向一个负数,这就是类似哈希表的实现原理的操作。
step 3:最后遍历数组的时候碰到的第一个非负数,它的下标就是没有出现的第一个正整数,因为它在之前的过程中没有被修改,说明它这个下标对应的正整数没有出现过。

import java.util.*;

public class Solution {
    public int minNumberDisappeared (int[] nums) {
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            if (nums[i] <= 0) nums[i] = n + 1;
        }
        for (int i = 0; i < n; i++) {
            if (Math.abs(nums[i]) <= n) {
                nums[Math.abs(nums[i]) - 1] = -Math.abs(nums[Math.abs(nums[i]) - 1]);
            }
        }
        for (int i = 0; i < n; i++) {
            if (nums[i] > 0) {
                return i + 1;
            }
        }
        return n + 1;
    }
}

2.4 三数之和

在这里插入图片描述
最主要的是判别重复与否,通过三个来做,判别前后的i、l和r上下两个数是不是相同,是的话就跳过。注意这里i只能与前一个做判断,因为存在-10、-10、20这种选项。

import java.util.*;

public class Solution {
    public ArrayList<ArrayList<Integer>> threeSum(int[] num) {
        ArrayList<ArrayList<Integer>> res = new ArrayList<>();
        if (num.length < 3) {
            return res;
        }
        Arrays.sort(num);
        
        int n = num.length;
        for (int i = 0; i < n - 2; i++) {
            if (i > 0 && num[i - 1] == num[i]) {
                continue;
            }
            int l = i + 1, r = num.length - 1;
            while (l < r) {
                if (num[l] + num[r] + num[i] > 0) r--;
                else if (num[l] + num[r] + num[i] < 0) l++;
                else {
                    ArrayList<Integer> tmp = new ArrayList<>();
                    tmp.add(num[l]);
                    tmp.add(num[r]);
                    tmp.add(num[i]);
                    res.add(tmp);
                    while (num[l] == num[l + 1] && l + 1 < r) l++;
                    while (num[r] == num[r - 1] && r - 1 > l) r--;
                    l++;
                    r--;
                }
            }
        }
        return res;
    }
}

3 知识点总结

  • 数组中只出现一次的两个数字:位运算
  • 数组中出现次数超过一般的数字:投票算法
  • 缺失的第一个正整数:原地hash算法
  • 三数之和:双指针

其实感觉hash没啥特殊的内容,但是hash在其他算法中也非常常用,需要时刻记住这个数据结构。

4 总结

坚持下去,会更强的。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值