代码随想录算法训练营第六天 | 哈希表理论基础 、Leetcode 242 有效的字母异位词、349 两个数组的交集、202 快乐数、1 两数之和

目录

哈希表理论基础

Leetcode 242 有效的字母异位词

Leetcode 349 两个数组的交集

Leetcode 202 快乐数

Leetcode 1 两数之和 

小结


哈希表理论基础

 文章链接:代码随想录_哈希表理论基础

定义:哈希表是根据关键码的值而直接进行访问的数据结构。(简单来说就是一个数组,数组的索引下标就是所说的关键码)

  • 那么哈希表能解决什么问题呢?一般哈希表都是用来快速判断一个元素是否出现集合里如果是正常的数组和链表,如果要找到目标元素,要从头到尾一一遍历。
  • 但是哈希法也是牺牲了空间换取了时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。

哈希函数:一种映射

哈希碰撞:多个内容映射到一个hashCode的情况;有两种解决方法:拉链法、线性探测法。

  • 拉链法:冲突元素全部被储存

        

  • 线性探测法:使用线性探测法,一定要保证tableSize大于dataSize。 我们需要依靠哈希表中的空位来解决碰撞问题。

        

常见的三种哈希结构:

  • 数组
  • set (集合)
  • map(映射)

Leetcode 242 有效的字母异位词

题目链接:Leetcode_242_有效的字母异位词

文档讲解:代码随想录_有效的字母异位词

视频讲解:b站讲解

数组也是哈希表的实现方式之一。使用数组来做哈希的题目,是因为题目都限制了数值的大小。

第一想法:遍历两个字符串,创建两个数组,各自统计每个字符串中各个字符出现的次数,然后比较两个字符串的个字符出现的次数(即两个数组的值)是否相同。

class Solution {
    public boolean isAnagram(String s, String t) {
        int[] record1 = new int[26];
        int[] record2 = new int[26];
        for(int i=0;i<s.length();i++){
            //charAt(i):输出第i个位置字符的值,输出的是字符
            record1[s.charAt(i)-'a']++;
        }
        for(int i=0;i<t.length();i++){
            //charAt(i):输出第i个位置字符的值,输出的是字符
            record2[t.charAt(i)-'a']++;
        }
        for(int i=0;i<26;i++){
            if(record1[i]!=record2[i]){
                return false;
            }
        }
        return true;
    }
}

学习记录:

可以只使用一个数组,遍历第一个字符串的时候,数组值+1;遍历第二个字符串的时候,数组对应位置的值-1;最后判断数组值的总和是否为0。

class Solution {
    public boolean isAnagram(String s, String t) {
        int[] record = new int[26];
        for(int i=0;i<s.length();i++){
            //charAt(i):输出第i个位置字符的值,输出的是字符
            record[s.charAt(i)-'a']++;
        }
        for(int i=0;i<t.length();i++){
            //charAt(i):输出第i个位置字符的值,输出的是字符
            record[t.charAt(i)-'a']--;
        }
        for(int i=0;i<26;i++){
            if(record[i]!=0){
                return false;
            }
        }
        return true;
    }
}

Leetcode 349 两个数组的交集

题目链接:Leetcode_349_两个数组的交集

文档讲解:代码随想录_两个数组的交集

视频讲解:b站讲解

第一想法:没什么想法

学习记录:

        题目虽然限制了数值范围,但是哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。所以此处使用set来解决此问题。

        整体思路就是将第一个数组建立成一个哈希表,然后遍历第二个数组的内容进行比较,然后返回二者去重后的交集。

JAVA中HashSet的使用

 使用集合前,需要用import语句导入Set接口,以及它的实现类HashSet

import java.util.Set; // 导入Set
import java.util.HashSet; // 导入HashSet

// 创建一个HashSet实例
Set<String/Integer> set = new HashSet<>();

set结构还提供了一些常见方法方便使用:

  • add(element):向集合中添加元素,如果元素已存在,则不会重复添加。
  • remove(element):从集合中移除指定元素。
  • isEmpty():判断集合是否为空。
  • size():返回集合中的元素数量。
  • clear():清空集合中的所有元素。
  • contains():用于检查是否有任何键映射到给定值元素(val_ele)中。

写法一:HashSet实现

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> reset = new HashSet<>();
        for(int i:nums1){
            set1.add(i);
        }
        for(int i:nums2){
            if(set1.contains(i)){
                reset.add(i);
            }
        }

        int[] rearr = new int[reset.size()];
        int j=0;
        for(int i:reset){
            rearr[j]=i;
            j++;
        }
        return rearr;
    }
}

写法二:数组实现

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        if(nums1==null || nums1.length==0 || nums2==null || nums2.length==0){
            return new int[0];
        }
        int[] arr1 = new int[1002];
        int[] arr2 = new int[1002];
        for(int i:nums1){
            arr1[i]++;
        }
        for(int i:nums2){
            arr2[i]++;
        }
        int count = 0;
        for(int i=0; i<1002; i++){
            if(arr1[i]>0 && arr2[i]>0){
                count++;
            }
        }

        int[] resarr = new int[count];
        int j = 0;
        for(int i=0; i<1002; i++){
            if(arr1[i]>0 && arr2[i]>0){
                resarr[j]=i;
                j++;
            }
        }
        return resarr;
    }
}

Leetcode 202 快乐数

题目链接:Leetcode_202_快乐数

文档讲解:代码随想录_快乐数

第一想法:用哈希表记录每一次计算的结果,判断这次的结果在以往有没有重复出现过,出现过的话就会进入循环,输出false,计算到1则输出true;但是我遇到了一个问题,n很大的情况下,怎么取出每一位数字,计算其每位数字的平方之和。

学习记录:

写一个专门的子函数用来计算每位数字的平方和,用一个循环先进行mod10的操作得到当前个位数字,然后整除10,去掉当前个位数字,不断执行上述操作,直到n=0。

class Solution {
    public boolean isHappy(int n) {
        Set<Integer> set1 = new HashSet<>();
        while(n != 1 && set1.contains(n)==false){
            set1.add(n);
            n = getn(n);
        }
        if(set1.contains(n)){
            return false;
        }
        return true;
    }

    private int getn(int n){
        int res = 0;
        while(n>0){
            int a = n % 10; //取模操作得到个位数
            res = res + a * a;
            n = n/10;  //除以10去掉当前的个位
        }
        return res;
    }
}


Leetcode 1 两数之和 

题目链接:Leetcode_1_两数之和

文档讲解:代码随想录_两数之和

视频讲解:b站讲解

第一想法:首先取第一个小于目标值的数字,然后计算差值,判断差值是否在哈希表中,如果存在就找到两外一个数的下标,不存在则取下一个小于目标值的数字,重复上述操作。但如何找下标呢?循环遍历感觉有点复杂。

学习记录:

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

JAVA中HashMap的使用

使用HashMap前需要导入对应的包文件

import java.util.Map; // 引入 Map 接口
import java.util.HashMap; // 引入 HashMap 实现类

Map<String, Integer> studentScores = new HashMap<>();

map结构还提供了一些常见方法方便使用:

  • put(key,value):将指定的键和值添加到map中,如果键已存在,则替换对应的值。
  • get(key):根据key获取对应的值value。
  • remove(key):根据key移除对应的键值对。
  • containsKey(key):检查map中是否包含key键。
  • containsValue(value):检查map中是否包含value值。
  • keySet():返回包含所有键的集合。
  • values():返回包含所有值的集合。
  • entrySet():返回包含所有键值对的集合。

解题思路:

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

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

在遍历数组的时候,只需要向map去查询是否有和目前遍历元素匹配的数值,如果有,就找到的匹配对,如果没有,就把目前遍历的元素放进map中,因为map存放的就是我们访问过的元素。(用此种方法求解可以少遍历一次,比我之前的想法快)

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] res = new int[2];
        if(nums == null || nums.length == 0){
            return res;
        }
        Map<Integer,Integer> map1 = new HashMap<>();
        for(int i=0; i<nums.length; i++){
            int temp = target-nums[i];
            if(map1.containsKey(temp)){
                res[0] = i;
                res[1] = map1.get(temp);
                break;
            }
            map1.put(nums[i],i);
        }
        return res;
    }
}

小结

小结一下三种常见哈希结构的使用情况:

  • 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
  • set是一个集合,里面放的元素只能是一个key,如果需要直到元素的下标就不合适。
  • map可以判断元素有没有遍历,又可以找到元素对应的下标。
  • 26
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值