代码随想录刷题笔记 DAY 6 | 有效的字母异位词 No. 242 | 两个数组的交集 No. 349 | 快乐数 No. 202 | 两数相加 No. 01

今日总结:今天是关于哈希表的题目,总体难度不算太大,今天准备再写一篇关于 Vuex 的博客。

Day 6

01. 有效的字母异位词(No. 242)

题目链接

代码随想录题解

1.1 题目

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

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

示例 1:

输入: s = “anagram”, t = “nagaram”
输出: true

示例 2:

输入: s = “rat”, t = “car”
输出: false

1.2 笔记

哈希表(Hash Table)是一种数据结构,用于实现字典(Dictionary)和映射(Map)等抽象数据类型。它通过哈希函数将键(key)映射到哈希表中的特定位置,以便快速定位和检索值(value)。哈希表的主要思想是将键转换为索引,使得在理想情况下可以在常量时间内(O(1) 的时间复杂度)查找或插入元素。

哈希表的核心组成部分包括:

  1. 哈希函数(Hash Function): 这是哈希表的关键部分,它将键转换为哈希码或哈希值。理想的哈希函数应该将不同的键映射到不同的哈希值,尽可能避免冲突(多个键映射到同一个位置)。
  2. 哈希表或哈希桶(Hash Table / Hash Bucket): 这是存储实际数据的地方。哈希表由一个数组构成,每个位置通常被称为“桶”,存储着键值对或者指向键值对的指针。
  3. 解决冲突的方法: 当不同的键经过哈希函数映射到相同的位置时,就会发生冲突。解决冲突的方法有很多种,常见的包括开放定址法(如线性探测和二次探测)和链表法(或者更高效的形式,如使用红黑树)。

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

对于上面的题目暴力解法就是两层 for 循环,记录字符是否重复出现,时间复杂度为 O(n^2)

这道题可以通过哈希表的方式解题,因为上面提到,哈希表可以快速的判断一个元素是否出现在集合里,所以如果两个字符串的长度相同,且各个字母的出现次数也相同就说明他们两个互为字母异位词。

我们知道,小写字母的 ASCII 码值是相邻的,一个长度为 26 的数组就可以存储这些字母出现的频率,将数组的下标作为索引,将数组元素值作为值就可以快速的查找。

首先判断两个字符串的长度是否相同,如果不同直接返回 false 之后同时循环遍历两个数组,如果字符串 1 中出现了就将索引加一,字符串 2 中出现则减一,最后我们去检查这个数组,如果出现了非 0 的值,说明这两个字符串不是互为异位词。

1.3 代码
class Solution {
    public boolean isAnagram(String s, String t) {
        // 将字符串转化为字符数组
        char[] charArray1 = s.toCharArray();
        char[] charArray2 = t.toCharArray();
        int length = charArray1.length;
        // 检测长度
        if (charArray2.length != length) {
            return false;
        }
        int[] hash = new int[26]; // 哈希数组
        
        for (int i = 0; i < length; i++) {
            hash[charArray1[i] - 'a']++;
            hash[charArray2[i] - 'a']--;
        }
        for (int i = 0; i < hash.length; i++) {
            if (hash[i] != 0) {
                return false;
            }
        }
        return true;
    }
}

02. 两个数组的交集(No. 349)

题目链接

代码随想录题解

2.1 题目

349. 两个数组的交集

给定两个数组 nums1nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]

示例 2:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的

提示:

  • 1 <= nums1.length, nums2.length <= 1000
  • 0 <= nums1[i], nums2[i] <= 1000
2.2 笔记

也是一道非常简单的问题,和上面题目的思想相同,我们先来看数组的解法,之后再通过集合去简化。

题目中已经限定了数组中元素的大小,所以我们直接将哈希数组声明为长度为 1000 的数组即可,这道题易错点是是否考虑了去重,所以我们遍历第一个数组,将出现的数字作为索引,值我们统一设为 1,再去遍历第二个数组,这时候就要注意了,我们必须保证结果集中只添加了一次,所以给出如下的判断语句:

if (hash[nums2[i]] == 1 && ++hash[nums2[i]] == 2) {
	list.add(nums2[i]);
}

只能是 2 的时候再接收,如果后续为 3 或者其他数字说明我们加重了。

2.3 代码
class Solution {
    int[] hash = new int[1000]; // 哈希数组
    public int[] intersection(int[] nums1, int[] nums2) {
        List<Integer> list = new ArrayList<>(); // 结果列表
        for (int i = 0; i < nums1.length; i++) {
            hash[nums1[i]] = 1;
        }
        for (int i = 0; i < nums2.length; i++) {
            // 保证不会重复
            if (hash[nums2[i]] == 1 && ++hash[nums2[i]] == 2) {
                list.add(nums2[i]);
            }
        }
        // 将结果转化为数组
        int index = 0;
        int res[] = new int[list.size()];
        for(int i : list)
            res[index++] = i;
        return res;        
    }
}
2.4 拓展 —— 利用 Set 解题
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];
        }
        Set<Integer> set1 = new HashSet<>();
        Set<Integer> resSet = new HashSet<>();
        //遍历数组1
        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:另外申请一个数组存放setRes中的元素,最后返回数组
        int[] arr = new int[resSet.size()];
        int j = 0;
        for(int i : resSet){
            arr[j++] = i;
        }
        
        return arr;
    }
}

和上面数组的解法时间是略高于前面的方法的,因为题目中限制了数字的大小,但如果很大的话,集合解法是优于数组的。

03. 快乐数(No. 202)

题目链接

代码随想录题解

3.1 题目

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n快乐数 就返回 true ;不是,则返回 false

示例 1:

输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

示例 2:

输入:n = 2
输出:false

3.2 笔记

也是一道比较简单的题目,唯一的难点可能就是如何求各位置上的平方和

我们来分析一下这道题目,一个数字只有两种情况:1. 经过有限次的平方加和变为了 1 2. 陷入循环,那我们如何判断是否陷入了循环呢?

就看一个和是否出现过,如果出现过两次则说明一定陷入了循环。

理解了这些,代码就非常好写了

3.3 代码
class Solution {
    public boolean isHappy(int n) {
        Set<Integer> record = new HashSet<>();
        int x = 0; // 每一位上的数字
        int sum = 0; // 每一次循环的和
        // 检测是否重复或者为 1
        while (sum != 1 && !record.contains(n)) {
            x = 0;
            sum = 0;
            record.add(n); // 放入集合中
            while (n > 0) {
                x = n % 10; 
                sum += x * x; 
                n = n / 10;               
            }
            n = sum;
        }
        return sum == 1;
    }
}

04. 两数相加(No. 01)

题目链接

代码随想录题解

4.1 题目

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

4.2 笔记

又是这道经典的梦开始的地方,这里我们来介绍这道题的哈希解法.

回顾一下,什么时候用哈希表?就是我们判断一个数在之前有没有出现过,在这道题里面,我们要判断的就是target - nums[i] 在我们之前的遍历中是否出现过,如果出现过就表明我们找到了这个组合,将这两个下标直接返回即可

我们可以通过 Map 来同时存储数字的下标和数值,也可以直接从头开始遍历求解.

4.3 代码
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> map = new 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;
	}
}
  • 23
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

*Soo_Young*

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值