Day05|哈希章节

文章介绍了哈希法在查找元素出现情况的应用,包括数组、Set(HashSet,LinkedHashSet,TreeSet)和Map(HashMap,LinkedHashMap,TreeMap)的使用,以及解决字母异位词、数组交集、快乐数和两数之和等问题的解决方案。
摘要由CSDN通过智能技术生成

哈希概览

一、什么时候使用哈希法:

        遇到需要判断一个元素是否出现过的场景也应该第一时间想到哈希法

二、哈希法的结构

        1.数组

        2.set:(单列集合,只存放value)

                1)HashSet:无序、不重复、无索引

                2)LinkedHashSet:有序、不重复、无索引

                3)TreeSet:可排序、不重复、无索引

        3.map:双列集合(存入的是一对Key和Value)

                1)HashMap:特点是由键决定的:无序、不重复、无索引。

                2)LinkedHashMap:特点是由键决定:有序、不重复、无索引。

                3)TreeMap:特点是由键决定:不重复、无索引、可排序

        


242.有效的字母异位词:

初始思路&&题解复盘:

        这道题主要是有巧解:也就是定义一个数组,存储26个字母,遍历第一个字符串的时候相应的地方++,然后遍历第二个字符串的时候相应的地方减减,用增强for遍历最后数组中的每个元素,如果有元素的数值不为0则说明不是字母异位词。

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

    }
}

349. 两个数组的交集

初始思路:

        有了上一道题作为背景,这道题自然联想到找一个数组存第一个数组的每个数的出现情况,再找一个数组存第二个数组的每个数的出现情况,然后判断重复的情况,考虑到数的范围比较广没办法像26个字母一样用比较小的空间,所以为了避免空间浪费,这里使用set,将第一个数组中的每个元素存入set1,然后将第二个数组中的元素继续存入set1中,考虑到set的去重机制,如果存入失败的话,就代表第二个数组中的该元素是和一中重复的,然后将其存入专门为了result new的Hashset。

这是初始作答,但是没有考虑到第二个数组中有重复元素出现的情况,就比如如下输入的时候就会出现错误。

所以修改答案, 将第一个数组存入set1,将第二个数组存入set2,现在两个set都是没有重复元素的,然后再将set2中的元素存入set1中,如果存入失败代表是重复元素。

题解复盘: 

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();//lambda表达式写法
        //return resSet.stream().mapToInt(Integer::intValue).toArray();//函数式接口写法

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

1)首先我们可以看到对输入做了一个输入是否有效的判断

2)忘记set有contains函数了!!这样就可以直接比我少创建一个hashset

3)学stream的时候只接触过map,还没接触过maptoint

Java 语法小记-CSDN博客

这里可以补充学习一下


202.快乐数(也没有很快乐呜呜)

初始思路:

获取输入数字的每一位,将其平方进行相加sum,获取每一位之后,判断sum是否为1,如果不为就将n赋值为sum,继续循环,知道sum==1,return true,但是这样有一个问题!我找不到false的出口!!

 题解复盘:

题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现,这对解题很重要!

正如:关于哈希表,你该了解这些! (opens new window)中所说,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了

使用哈希法,来判断这个sum是否重复出现,如果重复了就是return false(这就是出口!!), 否则一直找到sum为1为止。

class Solution {
    public boolean isHappy(int n) {
        //获取每个位置上的数字
        int sum = 0;
        HashSet<Integer> hs = new HashSet<>() ;
        while(true){
            sum = 0;
            while(n>0){
                int ge = n%10;
                n = n/10;
                sum = sum + ge*ge;
            }
            if(sum==1){return true;}
            if(hs.contains(sum)){return false;}
            else{hs.add(sum);
                    n = sum;}
         
        }
        
    }
}

这里没有像代码随想录中的题解一样包装成函数,同时每一次更新n的时候进行下一次求和运算之前将sum更新为0.


1.两数之和(注意更优解):

初始思路:

        咱就是说直接一整个暴力解法,将数组中每两个数都加起来看等于不等于value。

class Solution {
    public int[] twoSum(int[] nums, int target) {
        //HashMap<Integer,Integer> hm = new HashMap<>();
        HashSet<Integer> hs = new HashSet<>();
        for(int i = 0;i<nums.length-1;i++){
            for(int j = i+1;j<nums.length;j++){
                if(nums[i]+nums[j]==target){
                  hs.add(i);
                  hs.add(j);
                }
            }
        }
        int[] result = hs.stream().mapToInt(Integer::intValue).toArray();
        return result;
    }
}

题解复盘:

1)为什么要想到使用哈希法?

        因为想要在列表中查询是否遍历过该元素对应了哈希表使用原则查询一个元素是否存在。

2)为什么要使用map?

        因为既想存这个数值,又想存这个数值对应的索引。

3)map的作用?

        存储遍历过的元素,方便后续查询。

4)map中的key存放什么value存放什么?

        key存放这个数值,value存放对应的索引。

但是我感觉这个思想也挺重要的

 int temp = target - nums[i];   // 遍历当前元素,并在map中寻找是否有匹配的key

不是去找哪两个数相加等于target,而是去看一个范围内是否有数值满足可以和当前的数相加等于target。

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遍历的语法:

1)键找值:

Map<String,String> map = new HashMap<>();

Set<String> keys = map.keySet();

for(String key:keys)

{

        String value = map.get(key)

}
2)键值对

Map<String,String> map = new HashMap<>();

Set<Map.Entry<String,String>> entries = map.entrySet();

for(Map.Entry<String,String>> entry: entries)

{        String key = entry.getKey();

         String value = entry.getValue();

}

3)lambda表达式:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值