代码随想录day6

哈希表理论基础

哈希表

● 数组就是一张哈希表,通过下标可以直接访问数组中的元素
● 哈希表用来判断一个元素是否出现在集合里
● 学生名字是否在学校里,索引直接查询,O(1)
● 本质上是牺牲空间换取时间

哈希函数

● 把学生姓名转化为数值,可能大于哈希表大小,再进行取模运算,保证学生姓名落在哈希表上
● 但学生数量可能大于哈希表大小,产生哈希碰撞

哈希碰撞

● 多个元素映射到了同一个位置

拉链法

● 发生冲突的元素存储在链表中
● 要选择适当的哈希表大小,数组空值太多浪费内存,链表太长查找浪费时间

线性探测法

● 保证哈希表大小大于元素数量,依靠哈希表中的空位解决问题
● 下一个位置存放多余元素的信息

常见的三种哈希结构

● 数组
● set
● map

242.有效的字母异位词

● 力扣题目链接
● 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

思路

● 使用哈希表,时间复杂度O(n) 空间复杂度O(1)

代码

class Solution {
    public boolean isAnagram(String s, String t) {
        int[] hash = new int[26]; // 使用数组即可,长度不超过26
        for (char c : s.toCharArray()) {
            hash[c - 'a']++; // 遍历s,把对应位置元素++
        }
        for (char c : t.toCharArray()) {
            hash[c - 'a']--; // 遍历t,把对应位置元素--
            if (hash[c - 'a'] < 0) return false; // t比s多了某个字母,返回false
        }
        for (int num : hash) {
            if (num != 0) return false; // 结束再遍历一遍,如果s比t多了某个字母,返回false
        }
        return true;
    }
}
// 使用hashMap也可以,但慢一些
class Solution {
    public boolean isAnagram(String s, String t) {
        Map<Integer, Integer> hash = new HashMap();
        for (char c : s.toCharArray()) {
            hash.put(c - 'a', hash.getOrDefault(c - 'a', 0) + 1); // 把k对应的v + 1
        }
        for (char c : t.toCharArray()) {
            if (!hash.containsKey(c - 'a')) return false; // 如果没有对应的k,返回false
            hash.put(c - 'a', hash.get(c - 'a') - 1); // 把k对应的v - 1
            if (hash.get(c - 'a') == 0) hash.remove(c - 'a'); // 如果v减为0,删掉k
        }
        return hash.isEmpty(); // 如果map为空,说明符合要求
    }
}

349. 两个数组的交集

● 力扣题目链接
● 题意:给定两个数组,编写一个函数来计算它们的交集。

思路

● 使用set接收一个集合并去重,然后遍历另外的集合,求交集
● 最好stram流处理
● 注:set中,如果已经有元素1,再add元素1,会返回false,对集合没有影响,也不会报错
● 时间复杂度O(m + n) 空间复杂度O(n)

代码

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        Set<Integer> hash = new HashSet();
        Set<Integer> res = new HashSet();
        for (int num : nums1) { // 遍历nums1并去重
            hash.add(num);
        }
        for (int num : nums2) { // 遍历nums2,如果元素是交集中的,加入res
            if (hash.contains(num)) res.add(num);
        }
        return res.stream().mapToInt(x -> x).toArray(); // 转为数组
    }
}
// 使用数组也可以
class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        int[] hash = new int[1005];
        Set<Integer> res = new HashSet();
        for (int num : nums1) {
            hash[num] = 1;
        }
        for (int num : nums2) {
            if (hash[num] == 1) res.add(num);
        }
        return res.stream().mapToInt(x -> x).toArray();
    }
}

202. 快乐数

● 力扣题目链接
● 编写一个算法来判断一个数 n 是不是快乐数。
● 「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
● 如果 n 是快乐数就返回 True ;不是,则返回 False 。

思路

● 不断循环,拿到下一个数字,看是否之前出现过(在set中),出现过返回false,如果发现结果为1,结束循环,返回true
● 时间复杂度O(logn) 空间复杂度O(logn)

代码

class Solution {
    public boolean isHappy(int n) {
        Set<Integer> hash = new HashSet();
        while (n != 1) {
            if (hash.contains(n)) return false; // 一旦发现出现过n,不是快乐数
            hash.add(n); // 添加元素
            n = getNextNum(n); // 拿到下一个数字
        }
        return true; // n = 1,退出循环,是快乐数
    }
    private int getNextNum(int n) { // 返回n各位数字平方和
        int res = 0;
        while (n != 0) { // 注意这里的循环考虑
            int temp = n % 10;
            res += temp * temp;
            n = n / 10;
        }
        return res;
    }
}

1. 两数之和

● 力扣题目链接
● 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
● 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

思路

● 使用HashMap即可,k是数组中的元素,v是元素位置
● 遍历数组,如果map中有tar - nums[i] 这个k,找到了,返回新数组即可
● 如果没有,别忘了put进去
● 时间复杂度O(n) 空间复杂度O(n)

代码

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> hash = new HashMap();
        for (int i = 0; i < nums.length; i++) {
            if (hash.containsKey(target - nums[i])) {
                return new int[]{hash.get(target - nums[i]), i};
            }
            hash.put(nums[i], i);
        }
        return null;
    }
}

你可能感兴趣的:(代码随想录,哈希算法,散列表,算法)