力扣刷题Day5

哈希表基础

什么是Hash表?

哈希表是根据关键码的值而直接进行访问的数据结构。

直白来讲其实数组就是一张哈希表 - 哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素。

哈希表能解决什么问题呢,一般哈希表都是用来快速判断一个元素是否出现集合里。

Hash函数

哈希表2

一般hashcode是通过特定编码方式,可以将其他数据格式转化为不同的数值,也就找到对应hash表中的index。

Hash碰撞

两个元素的hash函数指向hash表中相同的位置。

哈希表3 

Hash碰撞解决办法 - 拉链法 和 线性探测法

拉链法

哈希表4

注意:其实拉链法就是要选择适当的哈希表的大小,这样既不会因为数组空值而浪费大量内存,也不会因为链表太长而在查找上浪费太多时间。 

线性探测法

哈希表5

依靠哈希表中的空位来解决碰撞问题 >> 一定要保证tableSize大于dataSize

例如冲突的位置,放了小李,那么就向下找一个空位放置小王的信息。所以要求tableSize一定要大于dataSize ,要不然哈希表上就没有空置的位置来存放 冲突的数据了。

三种常见的Hash结构:

  1. 数组
  2. 集合 set
  3. 映射 map

242. 有效的字母异位词

题目:力扣

 第一反应是采用Hashmap进行储存s中的字母出现的频率,然后储存t中的出现频率进行对比,但是这样其实和暴力解法有点像。

参考了其他解法,可以把t中出现的字母在储存s的map中进行搜索,然后-1,这样如果相同的情况下,那肯定是最后为0的,不相同的话,这个字母在map中的出现频率肯定<0。

这样实现之后仍然没有全部通过,"ab","a"这样的例子测试为true。

然后发现还需要一个前提条件 - 字符串必须是长度相等的。

    public boolean isAnagram(String s, String t) {

        if(s.length() != t.length()){
            return false;
        }

        HashMap map = new HashMap<>();
        for(int i=0; i

其他解法:

对s和t中的字符进行排序,然后判断两个字符串是否相等,如果不相等则为false

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(str2);
        return Arrays.equals(str1, str2);
    }
}

该题中的用例只有小写字母,类似hashmap的做法,创建一个长度为26的数组代表从a-z的字母,使用

s.charAt(i) - 'a'

计算出字符在数组中的位置,然后+1;而对于t则是计算出字符在数组中的位置,然后-1。

若有字符的频率<0, 则为false。

也需要注意前提,两个字符的长度必须相等。

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

参考资料:

力扣 ,代码随想录

349. 两个数组的交集

采用两个集合 - 一个集合储存set1的元素,一个集合储存set1中包含set2的元素 - 将set转化成数组。

这里注意代码的简洁 - 使用Stream进行set到数组的转换

 public int[] intersection(int[] nums1, int[] nums2) {
       if(nums1 == null || nums1.length == 0 ||nums2 == null || nums2.length == 0){
           return new int[0];
       }
       
       HashSet set1 = new HashSet<>();
        for(int i=0; i set2 = new HashSet<>();
        for(int i=0; i x).toArray();

    }

202. 快乐数

题目:力扣

这道题主要是理解题意:可能会无限循环不能到1;可能会到1

无限循环说明重复

因此判断循环终止的条件是 是否到1 或者是否有重复 --> 使用集合

在实现的时候对于循环条件判断有些问题

对于取n的每个位的数,开始循环采用

while(n/10>0)

但是发现在对个位数进行判断的时候 - n/10是直接等于0的也就跳过了

因此循环条件改为

while(n!= 0 && n/10 >= 0)

其实是等同于可以直接用 n>0这个条件的 

所以整体代码为

class Solution {
    HashSet set = new HashSet<>();//set储存n
    public boolean isHappy(int n) {
        while(n != 1 && !set.contains(n)){//如果n不在set中(没有循环),不等于1
            set.add(n);//n加入set中
            int sum =0;
            while(n>0){
                int x = n%10;//取高位数
                sum = sum + x*x;//累加
                n = n/10;//去掉最高位
            }

            n = sum;// 替换n
        }

        return n==1; //判断n是否等于1
    }
}

 参考资料:

代码随想录

 1.两数之和

题目:力扣

这道题其实如果直接使用暴力的话很容易解决。

但是在找target是否为数组中的两个数的和时;已知数组中的一个数A,那么B是能够求出来的

--> B=target -A

需要判断B是否在这个数组中,并且得知B的index

那么判断一个元素是否在一个集合中 - 可以采用Hash表的方法

这里因为还需要得知B的index,因此同时需要储存B以及B的index -- hashmap时最合适的

在遍历的时候,把元素以及元素的index放入map,同时判断map中是否存在B。若是存在则直接返回这两个下标。

这样只需要O(1)的时间就可以得到结果。 - 最多扫描一遍

class Solution {
    public int[] twoSum(int[] nums, int target) {
        HashMap map = new HashMap<>();
        for(int i=0; i

你可能感兴趣的:(leetcode刷题,leetcode,数据结构,算法)