代码随想录Day6--哈希表part01

不行了,今天玩了一天没学习,到了晚上才开始刷题。。看我今晚上能不能把它刷出来!

哈希表理论基础

首先切记!什么时候想到用哈希法,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。  

遇到哈希问题首先要想到的三种数据结构:数组、set、map。关于哈希表基础可以b站上看一下青大王卓老师的视频(查找模块),当时我的数据结构就是在她那里入门的哈哈哈。

哈希表就类似于数组,下标也是从0开始,可以通过哈希函数将某个数存放在表中的某个空间里。

开始做题!

注:每道题前面的题号都对应力扣上的题

242.有效的字母异位词(简单)

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

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

示例 1:

输入: s = "anagram", t = "nagaram"
输出: true

思考:第一次做哈希题,先看了一下卡哥思路,我们用哈希表来存放字符串s中字母的出现频率,之后减去字符串t中字母的出现频率,若最后表中存放的为0,则互为字母异位词。

代码实现:

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

总结:如果用哈希表做法的话,这道题其实也挺简单的。注意遍历字符串中某单个元素的方法。

349.两个数组的交集(简单)

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

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]

思考:这个题借用上题的方法,用哈希问题中的数组法很快就能做出来。当然用set方法比用数组更好,HashSet可以处理哈希法中出现数据量极大的情况,而数组法比较浪费内存,可以参考数组与List的比较。但我之前没接触过set,所以用数组法写了一遍。这里用的是卡尔的代码。

set分类:set、multi-set(这两类的底层实现为红黑树)、unordered-set(底层实现为哈希值)。

unordered-set做映射和取值操作的效率是最高的,所以本题可以用unordered-set来解答。

代码实现:

Hash数组法

class Solution {
    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;
    }
}

HashSet法

import java.util.HashSet;
import java.util.Set;

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) {
            return new int[0];
        }
        Set<Integer> set1 = new HashSet<>();
        Set<Integer> resSet = new HashSet<>();
        //遍历数组1
        for (int i : nums1) {
            set1.add(i);
        }
        //遍历数组2的过程中判断哈希表中是否存在该元素
        for (int i : nums2) {
            if (set1.contains(i)) {
                resSet.add(i);
            }
        }
      
        //方法1:将结果集合转为数组

        return resSet.stream().mapToInt(x -> x).toArray();
        
        //方法2:另外申请一个数组存放setRes中的元素,最后返回数组
        int[] arr = new int[resSet.size()];
        int j = 0;
        for(int i : resSet){
            arr[j++] = i;
        }
        
        return arr;
    }
}

总结:学会如何将Array和Set集合中存放的数据转化为数组。

202.快乐数(简单)

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

示例 1:

输入:n = 19
输出:true
 

思考:

这个题直接看示例就能理解了。因为不确定n未来会变成多少数,为了减少内存,首先先考虑Set方法,将求得的数字放进Set中。

那么如何进行查找呢?查找的条件是如果Set中出现了1,那么n就是快乐数。

如果一直没有出现n,那Set中的数字岂不是要一直加下去?当然不是,如果Set中出现了重复的数字,那么n就一定不是快乐数。

接下来照着这个思路写代码吧!

代码实现:

class Solution {
    public int Nextnum(int n){
        int getnext=0;
        while(n!=0){
            int x=(n%10)*(n%10);
            getnext+=x;
            n/=10;
        }
        return getnext;
    }
    public boolean isHappy(int n) {
        Set set=new HashSet<>();
        while (n!=1){
            if(set.contains(n))
        return false;
            set.add(n); //把下一个数存储到set中
            n=Nextnum(n);
        }
        return  true;
    }
}

总结:其实这道题我刚开始做的时候是把思路想错了,我想的竟然是把每一位数存在Set里。。。总之,还是得学会思维发散啊。熟练掌握哈希法中数组法与set的灵活运用。

1.两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

思考:其实这道题吧,首先我想到的是用暴力法解决,但我们要学会优化,所以这道题最好还是用哈希法来解答。我是第一次接触map,所以直接去看的卡尔视频讲解,放个链接在这。梦开始的地方,Leetcode:1.两数之和,学透哈希表,map使用有技巧!_哔哩哔哩_bilibili

代码实现:

public int[] twoSum(int[] nums, int target) {
    int[] res = new int[2];
    if(nums == null || nums.length == 0){
        return res;
    }
    Map<Integer, Integer> map = new HashMap<>();
    for(int i = 0; i < nums.length; i++){
        int temp = target - nums[i];   // 遍历当前元素,并在map中寻找是否有匹配的key
        if(map.containsKey(temp)){
            res[1] = i;
            res[0] = map.get(temp);
            break;
        }
        map.put(nums[i], i);    // 如果没找到匹配对,就把访问过的元素和下标加入到map中
    }
    return res;

总结:好好看视频,可以知道map中每次存放的是key和value。当然我们要分配好什么是key,什么是value。例如本题中打破了以往的惯性思维,将数组元素存放到key,而将下标值存放到value里。如果set解决的是找出数组元素,那么map解决的就是不仅要找出数组元素,还要找出对应的元素下标值。这里的代码也需要着重理解。

  • 37
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值