【代码详解+详细注释】小白都能看懂的力扣算法详解——哈希表(一)

!!本篇所选题目及解题思路均来自​​​​​​代码随想录 (programmercarl.com)

一 LC242.有效的字母异位词

题目要求:

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。

242. 有效的字母异位词 - 力扣(LeetCode)

题目分析:

本题可以使用暴力解法,即两个for循环遍历嵌套,统计a~z在s和t中各出现的次数,然后比较是否相等,听起来就知道时间复杂度不会低。那么我们换个角度考虑,可不可以用a~z作为索引值0~25,用次数统计作为数组中的元素呢?也就哈希表。这样我们只需要比较哈希表对应下标位置的元素是否相等就可以了。再进一步简化考虑,与其建立两个哈希表,依次比较,不如简化一下,使用一个哈希表完成,既然我们需要判断的仅仅是两个元素数值是否相等,那我们只要拿s中增加的数值减去t中增加的数值,如果最后的结果和原先相同,就说明s和t中的次数一样。整体思路完毕,接下来考虑细节。

首先考虑我们该如何构建哈希表?刚刚我们提到过,要用a~z作为索引值0~25,用次数统计作为数组中的元素。因为我们的数据量不大,且索引连续,所以我们直接采用数组作为底层实现就OK了。接下来考虑如何用a~z作为索引值,我们知道,在Java中的字符是用ASCII码表示的,a~z数值连续,而数组中的索引值从0开始连续,所以我们只要用所有字母减去字符a即可得到其对应的索引值。

代码实现如下:

    public boolean isAnagram(String s, String t) {
        int[] record = new int[26];
        for(int i = 0; i < s.length(); i++) {
            record[s.charAt(i) - 'a']++;
        }
        for(int i = 0; i < t.length(); i++) {
            record[t.charAt(i) - 'a']--;
        }
        for(int i = 0; i < record.length; i++) {
            if( record[i] != 0) {
                return false;
            }
        }
        return true;
    }

 我们可以进一步优化代码,将两次循环合并为一个,毕竟先加谁先减谁无所谓,最后结果不变。但是需要注意合并循环需要先判断两个字符串长度是否相等,否则就会出现越界问题。

public boolean isAnagram(String s, String t) {
        // 首先判断两个字符串长度是否相等,不等直接返回false
        if(s.length() != t.length()) {
            return false;
        }
        int[] record = new int[26];
        for(int i = 0; i < s.length(); i++) {
            record[s.charAt(i) - 'a']++;
            record[t.charAt(i) - 'a']--;
        }
        for(int i = 0; i < record.length; i++) {
            if( record[i] != 0) {
                return false;
            }
        }
        return true;
    }

这道题目也可以使用sort()方法进行排序后直接比较,感兴趣的同学可以自己实现试一下。

二 LC349 两个数组的交集

题目描述: 给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。

 题目分析:

本题和上题有异曲同工之妙,都是判断某个元素是否在一个集合中出现过。所以我们依旧可以沿用上题的思路,唯一的难点在于如何实现“去重”。根据官方的提示,可以看到:

  • 1 <= nums1.length, nums2.length <= 1000
  • 0 <= nums1[i], nums2[i] <= 1000

 两个数组的长度及元素内容都有范围限定,因此可以直接使用数组作为底层实现。数组长度略大于1001即可。这里我们把情况考虑得更全面一点,不考虑对于数组长度和元素大小的限定条件,则需要使用set实现。set适合索引值数值分散或很大的情况,因为set的索引值无需像数组一样必须连续。解题思路也很简单,遍历nums1,将nums1中存在的索引对应的数值置为1(其他默认为0),由此得到的hash表即为一个记录了nums1所有元素去重后的结果的表。之后再次遍历nums2,判断其中存在的索引对应的值是否为1,如果为1说明该索引为两个数组的交集,将其存在结果集中即可。这里需要注意,我们的结果集也需要是一个hash数组,因为我们同样需要实现“去重”的操作。最后将结果集转换为数组即可。

代码实现:

public int[] intersection(int[] nums1, int[] nums2) {
        Set<Integer> set1 = new HashSet<>(); // 
        Set<Integer> resSet = new HashSet<>(); // 结果集
        //遍历数组1,将数组1中的元素存储进去
        for (int i : nums1) {
            set1.add(i);
        }
        //遍历数组2,判断哈希表中是否存在该元素
        for (int i : nums2) {
            if (set1.contains(i)) {
                resSet.add(i);
            }
        }
        // 将set转换成数组
        int[] arr = new int[resSet.size()];
        int j = 0;
        for(int i : resSet){
            arr[j++] = i;
        }
        
        return arr;
    }

使用数组实现的代码如下,因为数组不好实现去重,所以我们直接使用两个数组分别将nums1、nums2中存在值的索引对应的数值置为1,之后比较相同索引值位置的元素是否均为1,若均为1则表示该值为交集中的元素: 

  public int[] intersection(int[] nums1, int[] nums2) {
        int[] hash1 = new int[1002];
        int[] hash2 = new int[1002];
        for(int i : nums1)
            hash1[i]++;
        for(int i : nums2)
            hash2[i]++;
        List<Integer> resList = new ArrayList<>();
        for(int i = 0; i < 1002; i++)
            if(hash1[i] > 0 && hash2[i] > 0)
                resList.add(i);
        int index = 0;
        int res[] = new int[resList.size()];
        for(int i : resList)
            res[index++] = i;
        return res;
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值