⑥ 哈希表

哈希表的数据结构

  • 数组(范围可控情况下使用)
  • set(数值较大情况下使用)
  • map(有键值对的情况下使用)

哈希表的应用场景:判断一个元素是否在集合中出现过。

242.有效的字母异位词

题目链接:https://leetcode.cn/problems/valid-anagram/

异位词定义:两个字符串的异位词等价于两个字符串排序后相等。

注意点:

两个字符串长度不相等直接返回flase

解法:

排序:对两个字符串进行排序,排序后判断字符串是否相等即可判断。

哈希表:定义一个能存放26个元素的哈希数组,统计字符串里面每一个字母出现的频率,然后在遍历第二个字符串的时候减去第二个字符串每个字母出现的频率,这个数组里面所有元素都是0的时候,说明两个字符串就是有效的字母异位词。

代码:

// 排序
class Solution {
    public boolean isAnagram(String s, String t) {
        if(s.length() != t.length()){
            return false;
        }
        char[] str1 = s.toCharArray();   // 将字符串转换为字符数组
        char[] str2 = t.toCharArray();
        Arrays.sort(str1);           // Arrays.sort()只能对数组进行排序
        Arrays.sort(str2);
        return Arrays.equals(str1,str2);
    }
}

// Hash法
class Solution {
    public boolean isAnagram(String s, String t) {
        if(s.length() != t.length()){   // 长度不同直接返回false
            return false;
        }
        // 定义一个长度为26的哈希数组,默认里面的值都为0
        int[] hash = new int[26];
        char[] str1 = s.toCharArray();   // 将字符串转换为字符数组
        char[] str2 = t.toCharArray();
        for(int i=0;i<s.length();i++){
            hash[str1[i]-'a']++;   // str1[i]-'a'得出相应的下标
        }
        for(int i=0;i<t.length();i++){
            hash[str2[i]-'a']--;
        }
        for(int i=0;i<26;i++){
            if(hash[i] != 0){
                return false;
            }
        }
        return true;
    }
}

349. 两个数组的交集

题目链接:https://leetcode.cn/problems/intersection-of-two-arrays/

注意点:

去重

不能直接用数组存储,数组需要提前定义长度,而结果的长度未知。

解题思路:

set方法:将nums1处理成哈希表的形式,nums2遍历每一个元素去查询在哈希表中是否出现过,如果有出现过,就将这个元素放进result集合中。

数组方法:定义一个比1000稍大的哈希数组,元素值默认为0,遍历nums1,以nums1中的元素值作为下标,遍历到的下标赋值为1,再遍历nums2,判断nums2中的元素有没有在哈希数组中出现过。出现过的元素就添加到哈希表中。

代码:

// 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<>();  // 存储nums1数组转成的哈希表
       Set<Integer> resSet = new HashSet<>();  // 存储结果的哈希表

       // 遍历数组1,将nums1中的元素存进哈希表set1中
       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:另外申请一个数组存放resSet中的元素,最后返回数组
        int[] arr = new int[resSet.size()];
        int j=0;
        for(int i : resSet){
            arr[j++] = i;
        }
        return arr;
    }
}

// 数组解法(测试数据<1000)
class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        int[] hash = new int[1005];   // 存放num1的哈希数组
        Set<Integer> resSet = new HashSet<>();  // 存放结果的哈希表,不用提前定义长度
        for(int i=0;i<nums1.length;i++){
            hash[nums1[i]] = 1;   // 以nums1中的元素值作为下标,遍历到的下标赋值为1
        }
        for(int i=0;i<nums2.length;i++){
            if(hash[nums2[i]] == 1){
                resSet.add(nums2[i]);
            }
        }
        return resSet.stream().mapToInt(x -> x).toArray();
    }
}

202.快乐数

题目链接:https://leetcode.cn/problems/happy-number/

注意点:

无限循环,求和的过程中,sum会重复出现。

解题思路:

定义一个函数,得到n拆分开来计算的结果,用哈希表set存储结果,循环判断结果是否等于1并且在不在哈希表中,false则添加还结果并继续计算,true则返回true。

代码:

class Solution {
    public boolean isHappy(int n) {
        // 用哈希表存储无限循环计算出来的值
        Set<Integer> record = new HashSet<>();
        while(n!=1 && !record.contains(n)){
            record.add(n);
            n = getNextNumber(n);
        }
        return n == 1;
    }


    // 得到下一个结果
    private int getNextNumber(int n){
        int sum = 0;
        while(n > 0){    
            int temp = n%10;   // 得到个位数
            sum += temp*temp;
            n = n/10;   // 得到去掉个位数的下一个值
        }
        return sum;
    }
}

1.两数之和

题目链接:https://leetcode.cn/problems/two-sum/

注意点:

判断这个元素是否出现过或者这个元素是否在这个集合中出现过的时候,用哈希表做处理。

本题不要求按顺序返回答案

map中的存储结构为 {key:数据元素,value:数组元素对应的下标}。

解题思路:

哈希法:在遍历数组的时候,只需要向map去查询是否有和目前遍历元素比配的数值,如果有,就找到的匹配对,如果没有,就把目前遍历的元素放进map中,因为map存放的就是我们访问过的元素。

代码:

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] result = new int[2];
        if(nums == null || nums.length == 0){
            return result;
        }

        // 暴力破解法
        // for(int i=0;i
        //     for(int j = i+1;j
        //         if(nums[i] + nums[j] == target){
        //             result[0] = i;
        //             result[1] = j;
        //         }
        //     }
        // }
        
        // 哈希表map解法
        Map<Integer,Integer> map = new HashMap<>();
        for(int i=0;i<nums.length;i++){
            int temp = target - nums[i];  // 记录另一个要查找的元素
            if(map.containsKey(temp)){
                result[1] = i;
                result[0] = map.get(temp);
                break;
            }
            map.put(nums[i],i); // 未找到匹配的值则添加当前元素
        }

        return result;
    }
}

你可能感兴趣的:(Java之路,散列表,leetcode,数据结构)