【力扣一刷】代码随想录day6( 哈希表基础、242、 349、202、1)

【哈希表理论基础 】

1、哈希表的作用

提高查找速度,普通遍历查找的时间复杂度为O(n),而哈希表实现O(1)

2、构建和使用哈希表的方法

  • 构建:将键(key)通过哈希函数转换成对应的存储位置(索引),然后将键值对存储在该位置。
  • 使用:key通过哈希函数计算得到索引,索引可以快速定位存储位置,从而实现高效的数据存取操作。

3、哈希碰撞

  • 定义:哈希碰撞指的是不同的键经过哈希函数计算后得到相同的哈希值,导致它们应该存储在哈希表中的相同位置。
  • 影响:哈希冲突会对哈希表的性能造成影响,需要额外的处理来解决这种冲突。
  • 常见的处理方法包括:链地址法(将哈希表的每个位置设置为一个链表当发生哈希碰撞时,将新的键值对插入到对应位置的链表中)、线性探测法(当发生哈希碰撞时,通过一定的规则寻找下一个可用的空位置来存储数据)。

4、Java中常见的哈希结构

  • 数组(array)
  • 集合(Collection,包含List和Set)
  • 映射(Map)

【242. 有效的字母异位词 】

方法一  利用HashMap

思路:key为单个字母,value为字母在字符串中出现的次数,分别对s和t建立两个HashMap,如果HashMap的内容完全一致,则返回true,否则返回false

class Solution {
    public boolean isAnagram(String s, String t) {
        if (s.length() != t.length()) return false;

        Map<Character, Integer> sAlphaNum = new HashMap<>();
        for (int i = 0;i < s.length(); i++){
            char c = s.charAt(i);
            if (sAlphaNum.containsKey(c)){
                sAlphaNum.put(c, sAlphaNum.get(c) + 1);
            }
            else{
                sAlphaNum.put(c, 1);
            }
        }
        System.out.println(sAlphaNum);

        Map<Character, Integer> tAlphaNum = new HashMap<>();
        for (int i = 0;i < t.length(); i++){
            char c = t.charAt(i);
            if (tAlphaNum.containsKey(c)){
                tAlphaNum.put(c, tAlphaNum.get(c) + 1);
            }
            else{
                tAlphaNum.put(c, 1);
            }
        }
        System.out.println(tAlphaNum);

        if (sAlphaNum.keySet().size() != tAlphaNum.keySet().size()) return false;

        for (Character c: sAlphaNum.keySet()){
            if (tAlphaNum.containsKey(c) && tAlphaNum.get(c).equals(sAlphaNum.get(c))){
                continue;
            }
            else{
                return false;
            }
        }

        return true;
    }
}

时间复杂度: O(n)

空间复杂度: O(n)

方法二   构建哈希表(更推荐)

思路:

1、定义一个长度为26的int型数组nums,可以利用字母的ASCII编码获取字母与数组下标的关系,构建哈希表。

2、分别遍历两个字符串,遍历第一个字符串的时候,就在出现的字母对应数组位置+1,遍历第二个字符串的时候,就在出现的字母对应数组位置-1。

3、遍历nums,如果存在不为0的值,则返回false,nums全为0则返回true。

class Solution {
    public boolean isAnagram(String s, String t) {
        int[] nums = new int[26];

        for (int i = 0; i < s.length(); i++){
            char c = s.charAt(i);
            nums[c - 'a']++; 
        }
        
        for (int i = 0; i < t.length(); i++){
            char c = t.charAt(i);
            nums[c - 'a']--;
        }

        for(int i = 0; i < nums.length; i++){
            if (nums[i] != 0){
                return false;
            }
        }
        return true;
    }
}

时间复杂度: O(n)

空间复杂度: O(1)  (因为数组长度固定为26,与输入字符串的长度无关)

【349. 两个数组的交集 】

方法一  利用HashSet

思路:

1、获取nums1数组的无重元素集合

2、遍历nums2数组,如果nums1数组的无重元素集合包含遍历到的元素,则添加进结果集合

3、将结果集合转换成结果数组并返回

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        // 排除特殊情况
        if (nums1 == null || nums2 == null || nums1.length == 0 || nums2.length == 0) return new int[0];

        // 获取nums1数组的无重元素集合
        HashSet<Integer> nums1Set = new HashSet<>();
        for (int i = 0; i < nums1.length; i++){
            nums1Set.add(nums1[i]);
        } 

        // 遍历nums2数组,如果nums1数组的无重元素集合包含遍历到的元素,则添加进结果集合
        HashSet<Integer> resSet = new HashSet<>();
        for (int i = 0; i < nums2.length; i++){
            if (nums1Set.contains(nums2[i])){
                resSet.add(nums2[i]);
            }
        }

        // 将结果集合转换成结果数组
        int[] res = new int[resSet.size()];
        int i = 0;
        for (int r: resSet){
            res[i++] = r;
        }
        return res;
    }
}

时间复杂度: O(n+m)

空间复杂度: O(n)

方法二  构建哈希表(利用题目的数值范围,更巧妙)

思路:根据题目给定的数值范围 0 <= nums1[i], nums2[i] <= 1000 构建哈希表

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        // 排除特殊情况
        if (nums1 == null || nums2 == null || nums1.length == 0 || nums2.length == 0) return new int[0];

        // 创建哈希表
        int[] hash1 = new int[1002]; // 1001种可能的取值,索引从0开始,1001+1=1002
        int[] hash2 = new int[1002];
        ArrayList<Integer> resList = new ArrayList<>();

        // 分别遍历两个表,遍历到的数字在对应位置+1
        for (int num1 : nums1){
            hash1[num1]++;
        }

        for (int num2 : nums2){
            hash2[num2]++;
        }

        // 如果某个数字对应两个表的位置都不为0,则该数字就是交集中的元素
        for (int i = 0; i < hash1.length; i++){
            if (hash1[i] > 0 && hash2[i] > 0){
                resList.add(i);
            }
        }

        // 将集合转成数组
        int i = 0;
        int[] res = new int[resList.size()];
        for (int r: resList){
            res[i++] = r;
        }

        return res;
    }
}

时间复杂度: O(n+m)

空间复杂度: O(n)

【202. 快乐数】

思路:

1、如果和计算为1,则这个数为快乐数;

2、如果和已经出现过,证明已经开始循环,则这个数不是快乐数;

关键就是判断当前的和是否之前出现过,可以利用HashSet判断。

class Solution {
    public boolean isHappy(int n) {
        // 用来存储每次的和
        Set<Integer> sumSet = new HashSet<>();

        // 循环的截止条件:
        // 1、如果出现n=1,则这个数为快乐数;
        // 2、如果sumSet已经包含了n,证明已经开始循环,则这个数不是快乐数;
        while (n != 1 && !sumSet.contains(n)){
            sumSet.add(n);
            n = nextNum(n);
        }
        return n == 1;
    }

    // 输入一个整数,求组成它的各个数字的平方和并返回
    private int nextNum(int n){
        int s = 0;
        while (n != 0){
            int last =  n % 10;
            s += last * last;
            n /= 10;
        }
        return s;
    }
}

时间复杂度: O(logn)

空间复杂度: O(logn)

【1. 两数之和 】

思路:

1、利用哈希表,记录列表中出现过的值及其下标,如果重复出现则不记录。

2、查找差值temp = target - nums[i]是否在前面遍历过的元素中出现,以获取返回值。

注意:

1、必须在将值及其坐标存入map之前,对该值进行差值存在判断,避免构成target的两个数的值相等(如:6=3+3)这种情况导致的返回值错误。

2、如果nums = [2, 4, 7, 8],target = 9,在遍历2时,map中的key没有7(或前面没出现过7),则继续遍历,直到遍历7,map中的key有2,才返回。

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();
        int[] res = new int[2];
        for (int i = 0; i < nums.length; i++){
            // 计算差值并查找,如果前面出现过,则获取结果退出循环
            int temp = target - nums[i];
            if (map.containsKey(temp)){
                res[0] = i;
                res[1] = map.get(temp);
                break;
            }

            // 如果前面没有出现过这个值,则将key=nums[i]和value=i存入map
            if (!map.containsKey(nums[i])){
                map.put(nums[i], i);
            }
        }
        return res;
    }
}

时间复杂度: O(n)

空间复杂度: O(n)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值