day06-哈希表01

什么时候想到用哈希法?

        当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法

 242.有效的字母异位词 

先看暴力的解法,两层for循环,同时还要记录字符是否重复出现,很明显时间复杂度是 O(n^2)

(leetcode测试用例会超出时间限制)

class Solution {
    //暴力法双重for循环 
    public boolean isAnagram(String s, String t) {
        if(s.length() != t.length()){
            return false;
        }
        //遍历一个字符串 第一个字符
        for(char c : s.toCharArray()){
            if(countChar(s,c) != countChar(t,c)){
                return false;
            }
        }
        return true;
    }

    private int countChar(String s,char c){
        int count = 0;
        //遍历第一个字符在整个字符串中出现的个数
        for(char cc : s.toCharArray()){
            if(cc == c){
                count ++;
            }
        }
        return count;
    }
}

字典解法

定义一个数组叫做record用来上记录字符串s里字符出现的次数。

需要把字符映射到数组也就是哈希表的索引下标上,因为字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下标0,相应的字符z映射为下标25。

再遍历 字符串s的时候,只需要将 s[i] - ‘a’ 所在的元素做+1 操作即可,并不需要记住字符a的ASCII,只要求出一个相对数值就可以了。 这样就将字符串s中字符出现的次数,统计出来了。

那看一下如何检查字符串t中是否出现了这些字符,同样在遍历字符串t的时候,对t中出现的字符映射哈希表索引上的数值再做-1的操作。

那么最后检查一下,record数组如果有的元素不为零0,说明字符串s和t一定是谁多了字符或者谁少了字符,return false。

最后如果record数组所有元素都为零0,说明字符串s和t是字母异位词,return true。

class Solution {
    public boolean isAnagram(String s, String t) {
        //定义一个26位英文字典
        int[] record = new int[26];
        //第一个字符串进行遍历字典+1 
        for(int i=0 ;i < s.length();i++){
            record[s.charAt(i)-'a']++; 
        }
         //第二个字符串进行遍历字典-1 
        for(int i=0 ;i < t.length();i++){
            record[t.charAt(i)-'a']--; 
        }
        //当字典数组全为0 表示为字母异位词
        for(int count : record){
            if(count != 0){
                return false;
            }
        }
        return true;
    }
}

349. 两个数组的交集 

看到需要去重唯一,不考虑输出结果顺序,就要想到用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<>();
        //遍历数组一 去重添加到set集合中
        for(int s : nums1){
            set1.add(s);
        }
        //遍历数组二 判断集合中是否包含数组元素 得到最总结果
        for(int i : nums2){
            if(set1.contains(i)){
                resSet.add(i);
            }
        }
        //将set集合转换为数组

        //方法一 申请一个数组用来存放resSet元素最后返回
        // int[] arr = new int[resSet.size()];
        // int j = 0;
        // for(int i : resSet){
        //     arr[j++] = i;
        // }
        // return arr;
        
        //方法二 使用stream流
        return resSet.stream().mapToInt(x->x).toArray();
    }
}

 202. 快乐数 

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

        重复会成环 使用Set来判断集合中是否出现过 

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 result = 0;
        while(n>0){
            int temp = n % 10;
            result += temp * temp;
            n = n / 10;
        }
        return result;
    }
   
}

 1. 两数之和 

暴力解法 双重for循环

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] res = new int[2];
        if(nums == null || nums.length == 0){
            return res;
        }
        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;
                    return res;
                }
            }
        }
        return res;
    }
}

map

本题其实有四个重点:

  • 为什么会想到用哈希表

        当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。

  • 哈希表为什么用map

        因为本题,我们不仅要知道元素有没有遍历过,还要知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适

  • 本题map是用来存什么的
  • map中的key和value用来存什么的

map目的用来存放我们访问过的元素,因为遍历数组的时候,需要记录我们之前遍历过哪些元素和对应的下标,这样才能找到与当前元素相匹配的(也就是相加等于target)

接下来是map中key和value分别表示什么。

这道题 我们需要 给出一个元素,判断这个元素是否出现过,如果出现过,返回这个元素的下标。

那么判断元素是否出现,这个元素就要作为key,所以数组中的元素作为key,有key对应的就是value,value用来存下标。

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

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

数组中同一个元素在答案里不能重复出现。key为元素 value为下标

map存放的就是我们访问过的元素

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] res = new int[2];
        Map<Integer,Integer> resmap = new HashMap<>();
        if(nums == null || nums.length == 0){
            return res;
        }
        for(int i=0 ;i<nums.length ;i++){
            int temp = target - nums[i];
            //如果集合中存在temp
            if(resmap.containsKey(temp)){
                res[0] = resmap.get(temp);
                res[1] = i;
                break;
            }
            //不存在 将当前遍历元素添加到map集合中去
            resmap.put(nums[i],i);
        }
        return res;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值