力扣刷题之哈希表(1) | 242. 有效的字母异位词、349. 两个数组的交集、202. 快乐数、1. 两数之和

Leetcode 242. 有效的字母异位词

题目链接

思路

暴力解法很容易想到,用两层for循环,同时记录重复出现的字母,时间复杂度为(n^2)。当要快速判断一个元素是否出现集合里的时候,可以考虑哈希法
由于本题出现的所有元素都只是小写字母a~z,它们在ASCII码表上的值是连续的。由此可以定义一个数组hash[26],数组其实就是一个简单哈希表,来存储字符串中每个字母出现的次数
遍历字符串s时,只需要将哈希表中 s[i] - ‘a’ 所在的元素+1 操作,并不需要记住每个字母都ASCII值,只要求出一个相对于’a’的数值就可以了。例如当s[i]='a’时,此时hash[0]++;当s[i]='c’时,此时hash[2]++。
遍历字符串t时,由于题目只需要判断两字符中各字母出现的次数是否相等,可以将字符串t中的各个字母映射哈希表索引上的数值-1
如果两者为有效的字母异位词,则哈希数组中每个元素为0;否则,就不是有效的字母异位词。

代码(Java)

写法1:哈希法

时间复杂度: O(n)
空间复杂度: O(1)

class Solution {
    public boolean isAnagram(String s, String t) {
         int hash[]=new int[26];//0~25分别存放26个字母出现的顺序
        char[] s_arr=s.toCharArray();
        char[] t_arr=t.toCharArray();
        for (int i=0;i<s_arr.length;i++){
            hash[s_arr[i]-'a']++;//根据ASCII码,遍历s的每个字母存入hash数组中
        }
        for (int i=0;i<t_arr.length;i++){
            hash[t_arr[i]-'a']--;//根据根据ASCII码,当t中的字母出现与s中相同字母时,数组中代表该字母的元素减1
        }
        for (int i=0;i<hash.length;i++){
            if (hash[i]!=0){//若符合字母异位词,则hash数组中的每个元素为0
                return false;
            }
        }
        return true;
    }
}

代码随想录链接

下面是代码随想录的文章链接与视频链接,帮助大家更好地理解这道题。
文章
视频

Leetcode 349. 两个数组的交集

题目链接

思路

这道题又是判断数据结构中某个元素是否出现,很容易用哈希表来解决。由于题目中强调输出结果中的每个元素一定是唯一的,也就是说输出的结果是去重的, 同时可以不考虑输出结果的顺序。
因为题目限制了元素的大小,所以使用数组来做这道题。如果没有限制元素的大小,就无法使用数组来做哈希表了,则用另一种结构体HashSet。另外,如果元素个数比较少,但分散、跨度非常大使用数组就造成空间的极大浪费
然而,HashSet是一个不允许有重复元素的集合,但由于HashSet 基于 HashMap 来实现的,所以HashSet把数值映射到Key上都要做hash计算的,所以速度比数组慢。

代码(Java)

写法1:Hash数组

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        int hash[]=new int[1003];
        Set<Integer> result=new HashSet<>();//存放结果,用set去重
        for (int i=0;i<nums1.length;i++){
            hash[nums1[i]]=1;//
        }
        for (int i=0;i<nums2.length;i++){
            if (hash[nums2[i]]==1){
                result.add(nums2[i]);
            }
        }
        return result.stream().mapToInt(x->x).toArray();
    }
}

写法2:HashSet

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        if(nums1.length==0||nums2.length==0||nums1==null||nums2==null){
            return new int[0];
        }
        Set<Integer> set1=new HashSet<>();
        Set<Integer> result=new HashSet<>();
        //将nums1的元素存入set1
        for (int i = 0; i < nums1.length; i++) {
            set1.add(nums1[i]);
        }
        //筛选nums2中与nums1相同的元素,存入result
        for (int i = 0; i < nums2.length; i++) {
            if (set1.contains(nums2[i]))
                result.add(nums2[i]);
        }
        //将set转化为数组
        return result.stream().mapToInt(x->x).toArray();
    }
}

代码随想录链接

下面是代码随想录的文章链接与视频链接,帮助大家更好地理解这道题。
文章
视频

Leetcode 202. 快乐数

题目链接

思路

前面我们提到,当需要快速判断一个元素是否出现集合里时,要考虑哈希法。而这道题目使用哈希法,因为在对n每个位置的数字求平方和sum的过程中,sum会重复出现,则需要哈希表来判断sum是否重复出现,如果重复了就return false,否则一直找到平方和为1。判断sum是否重复出现就可以使用HashSet

难点

  • 如何获取n每个位置的数字?
    这里可以拿具体的数字来模拟。假设有n=321,拿到末尾数1很容易,直接对n%10;接着要拿到数字2时,我们可以先让1消失,则n/=10此时n=32,再进行取模操作。

代码(Java)

class Solution {
    public boolean isHappy(int n) {
        Set<Integer> appearedNum = new HashSet<>();
        while(n!=1 && !appearedNum.contains(n)){
            appearedNum.add(n);
            n=getSum(n);
        }
        return n==1?true:false;
    }
    private int getSum(int n){//拿到每个位置的数字的平方和
        int sum=0;
        while (n>0){
            int temp = n%10;
            sum+=temp*temp;
            n/=10;
        }
        return sum;
    }
}

代码随想录链接

下面是代码随想录的文章链接,帮助大家更好地理解这道题。
文章

Leetcode 1. 两数之和

题目链接

思路

这道题的暴力解法很容易想到,也是Leetcode刷题“梦开始的地方”,两层for循环嵌套,此时的时间复杂度为O(n^2)。
前面我们提到,当需要快速判断一个元素是否出现集合里时,要考虑哈希法。本题,我们需要一个集合来存放遍历过的元素当遍历数组的元素时,还需要访问该集合。例如我们遍历到了一个数x,此时需要访问遍历过的元素集合,找到是否存在数值为(target-x)的元素。
不仅要知道元素有没有遍历过,还需要知道该元素对应的下标,所以这里需要使用 <key,value>结构 来存放,key存放元素value存放下标,所以使用 HashMap

难点

  • 为什么用key存放元素,value存放下标?
    因为要判断的是某元素是否出现过,而HashMap就是能快速查找key是否在该map中出现过,所以key存放元素,同时题目还需要返回元素下标,所以value存放下标。

代码(Java)

写法1:暴力解法

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] res = new int[2];
        for(int i=0;i<nums.length;i++){
            for(int j=i+1;j<nums.length;j++){
                if(nums[i]+nums[j]==target){
                    res[0]=i;
                    res[1]=j;
                    break;
                }
            }
        }
        return res;
    }
}

写法2:HashMap

class Solution {
    public int[] twoSum(int[] nums, int target) {
       if (nums.length==0 || nums==null){
            return new int[0];
        }
        Map<Integer,Integer> map=new HashMap<>();//存放已遍历过的元素
        int[] ret=new int[2];//结果数组
        for (int i=0;i<nums.length;i++){
            int temp = target-nums[i];//需要访问Map中是否有该元素
            if (map.containsKey(temp)){//在Map找到了该元素
                ret[0]=map.get(temp);//拿到Map中元素的下标存入结果数组
                ret[1]=i;
                break;
            }
            map.put(nums[i],i);//没找到,则把访问到的元素和下标加入到Map中
        }
        return ret;
    }
}

代码随想录链接

下面是代码随想录的文章链接与视频链接,帮助大家更好地理解这道题。
文章
视频

总结

今天学习了哈希表,当需要快速判断一个元素是否出现集合里时,要考虑哈希法。而哈希结构有三种,分别是数组、set、map
在上面的题目中,可以感受到三者的应用场景有所不同。采用哪一种还需要具体问题具体分析。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fuego91

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值