代码随想录算法训练Day6|LeetCode 242-有效字母异位词、LeetCode 349-两个数组的交集、LeetCode202-快乐数、LeetCode 1-两数之和

哈希表Hash table

一般哈希表用来快速判断一个元素是否出现在集合里

通过hashCode把名字转化为数值,一般hashcode是通过特定编码方式,可以将其他数据格式转化为不同的数值,这样就把学生名字映射为哈希表上的索引数字了。

哈希表是一种通过对于增删改查性能较好的结构,以hashset添加过程举例:

底层结构:

哈希表(数组、链表、红黑树)

1.创建hashset集合,内部会存在一个长度16的数组

2.调用集合的添加方法,会拿着对象的hashcode方法计算应存入的索引位置(哈希值%数组长度)

详细解释:拿着对象的hashcode方法得到原始哈希值,再拿着原始哈希值向右移动16位,做一次哈希扰动,然后拿着扰动后的值与原始哈希值做异或操作,来进行这种二次哈希操作,以期减少一些哈希冲突,在将来计算索引位置时避免太多的重复索引,将列表打散

在这里插入图片描述
哈希碰撞有两种解决方法, 拉链法(JDK8之后是尾插法)和线性探测法
哈希法解决问题一般有一下三种数据结构:
数组
set(集合)
map(映射)

有效的字母异位词

题目描述

力扣242-有效字母异位词

给定两个字符串 st ,编写一个函数来判断 t 是否是 s 的字母异位词。

**注意:**若 st 中每个字符出现的次数都相同,则称 st 互为字母异位词。

解题思路

算法公开课-网页

carl-有效的字母异位词-video

在这里插入图片描述

定义一个存放26个小写字母的整数数组 int hash[26]

 hash[s.charAt(i) - 'a']++

i=1,若索引1为字符’b’,则’b’-‘a’=1,则hash[1]++;hash索引1存放的是b出现的次数,最后比较数组 hash中的元素全0即可,时间复杂度为O(n),空间上因为定义是的一个常量大小的辅助数组,所以空间复杂度为O(1)。

自己解题

class Solution {
    public boolean isAnagram(String s, String t) {
        int[] hash = new int[26];//定义一个存放26个小写字母的整数数组hash
        for (int i = 0; i < s.length(); i++) {
            hash[s.charAt(i) - 'a']++;
        }
        for (int i = 0; i < t.length(); i++) {
            hash[t.charAt(i) - 'a']--;
        }
        for (int i = 0; i < 26; i++) {
            if (hash[i] != 0) {
                return false;
            }
        }
        return true;
    }
}

s.charAt(i) 返回指定索引处char值

s.length() 返回字符串长度

参考解题

/**
 * 242. 有效的字母异位词 字典解法
 * 时间复杂度O(m+n) 空间复杂度O(1)
 */
class Solution {
    public boolean isAnagram(String s, String t) {
        int[] record = new int[26];

        for (int i = 0; i < s.length(); i++) {
            record[s.charAt(i) - 'a']++;     // 并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
        }

        for (int i = 0; i < t.length(); i++) {
            record[t.charAt(i) - 'a']--;
        }
        
        for (int count: record) {
            if (count != 0) {               // record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
                return false;
            }
        }
        return true;                        // record数组所有元素都为零0,说明字符串s和t是字母异位词
    }
}

补充

String类相关的方法

查询API(String类的构造方法、字符串的遍历、截取、替换、切割、StringBuilder)

两个数组的交集

题目描述

力扣349-两个数组的交集

解题思路

代码随想录-思路

自己解题

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        Set<Integer> set1 = new HashSet<>();
        for (int num : nums1)
            set1.add(num);// 使用HashSet对数组去重

        Set<Integer> set2 = new HashSet<>();
        for (int num : nums2)
            set2.add(num);

        int[] output = new int[nums1.length];
        int index = 0;
        for (int num : set1) {
            if (set2.contains(num)) {
                output[index] = num;
                index++;
            }

        }
        System.out.println(index);
        return Arrays.copyOf(output, index);// 复制指定的数组,截取或用 null 字符填充(如有必要),以使副本具有指定的长度
    }
}
output[index++] = num;

//
output[index] = num;
index++;

参考解题

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];
        }
        HashSet<Integer> set1 = new HashSet<>();
        HashSet<Integer> resSet = new HashSet<>();
        // 遍历数组1
        for (int i = 0; i < nums1.length; i++) {
            set1.add(nums1[i]);
        }
        // 遍历数组2的过程中判断哈希表中是否存在该元素
        for (int i : nums2) {
            if (set1.contains(i)) {
                resSet.add(i);
            }
        }

        // 方法1:将结果集合转为数组

        return resSet.stream().mapToInt(x -> x).toArray();//stream 流

    }
}

补充

1.HashSet无序去重查询效率O(1),增删效率O(1),

2.Arrays工具类常用方法

在这里插入图片描述

3.HashSet常用方法

在这里插入图片描述

4.输入判断:

      if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) {
            return new int[0];
        }

快乐数

题目描述

力扣202-快乐数

解题思路

代码随想录
当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,---->哈希法

由于循环次数未知,所以使用while循环,则循环终止条件为:

 while (n != 1 && !record.contains(n))

1)当变为1,是快乐数,跳出循环。
2)是之前循环到过的数字(利用HashSet类的contains方法),跳出循环。
将下一次次循环的数字通过函数 getNextNumber解算

自己解题

class Solution {
    public boolean isHappy(int n) {
        Set<Integer> res = new HashSet<>();
        /*
         * 循环终止条件:
         * 1)当变为1,是快乐数,跳出循环。
         * 2)是之前循环到过的数字(利用HashSet类的contains方法),跳出循环
         */
        while (n != 1 && !res.contains(n)) {
            res.add(n);
            n = getNextNumber(n);
        }
        return n == 1;
    }

    private int getNextNumber(int n) {
        int res = 0;
        while (n > 0) {
            int temp = n % 10;// 数字拆分成每一位-->每次对10取余即可
            res += temp * temp;
            n = n / 10;
        }
        return res;
    }
}

参考解题

代码随想录-快乐数

补充

注意循环终止条件

两数之和

题目描述

力扣1-两数之和

解题思路

代码随想录
1.当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,---->哈希法

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

自己解题

Map<Integer, Integer> map = new HashMap<>();//建立一个HashMap,用于存放键、值

找元素是否出现,所以key存放元素。查的是下标,值value存放下标。

class Solution {
    public int[] twoSum(int[] nums, int target) {
        /*
         * 哈希法可以快速从目标数组中找到对应的值
         * map 是能在最快的时间内,判断这个key是否在map里出现过
         * 遍历的时候用一个map存数组的值和下标,因为我们是要看值是否遍历过所以,key应该为值,key-value:需要的是下标,因此value为下标
         * 而target - 当前遍历到的当前值nums[i] = cha差值,通过这个差值当作key来遍历map判断数组中是否遍历过该元素,从而得到目标的两个下标
         */
        Map map = new HashMap<Integer, Integer>();
        for (int i = 0; i < nums.length; i++) {
            int cha = target - nums[i];
            if (map.containsKey(cha)) {
                return new int[] { (Integer) map.get(cha), i };
            }
            map.put(nums[i], i);
        }
        return new int[2];//代码运行到这说明不存在,返回空整数数组
    }
}

参考解题

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<>();//建立一个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;
}

补充

HashMap常用方法

map.containsKey(key)查找key是否存在map集合中

map.get(key)

map.put(key,value)添加键值对
在这里插入图片描述
ps:部分图片和代码来自代码随想录Leetcode官网

  • 24
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值