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

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

什么时候用set 什么时候用数组?

使用数组来做哈希的题目,是因为题目都限制了数值的大小。

而这道题目没有限制数值的大小,就无法使用数组来做哈希表了。(后来限制了)

而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。

但直接使用set 不仅占用空间比数组大,而且速度要比数组慢,set把数值映射到key上都要做hash计算的。不要小瞧 这个耗时,在数据量大的情况,差距是很明显的。


 

class Solution {
    public boolean isAnagram(String s, String t) {
        // 用数组做哈希表
        int[] record = new int[26];
        // 用s.toCharArray()把String转为char数组,遍历
        for (char c : s.toCharArray()) {
            // Unicode -- Java中允许字符算术(‘b’-'a' = 98-97)
            // char之间进行算数操作返回的是int
            record[c - 'a']++;
        }

        for (char c : t.toCharArray()) {
            record[c - 'a']--;
        }

        for (int r : record) {
            if (r != 0) {
                return false;
            }
        }
        return true;
    }
}

注意toCharArray()的转换方法,注意for (char c : s.toCharArray())的遍历方法

Unicode -- Java中允许字符算术(‘b’-'a' = 98-97)

char之间进行算数操作返回的是int

349. 两个数组的交集

import java.util.HashSet;
import java.util.Set;

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        // 检查数组是否为null或空
        if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) {
            return new int[0];
        }

        Set<Integer> set1 = new HashSet<>();
        Set<Integer> set2 = new HashSet<>();

        for (int i : nums1) {
            set1.add(i);
        }
        for (int i : nums2) {
            if (set1.contains(i)) {
                set2.add(i);
            }
        }

        int[] arr = new int[set2.size()];
        int index = 0;
        for (int s : set2) {
            arr[index++] = s;
        }
        return arr;
    }
}

检查 nums1 == nullnums1.length == 0 两个条件看似有重叠,但它们实际上是检查两种不同的情况:

  1. nums1 == null: 这个条件检查 nums1 是否为 null。在 Java 中,尝试访问一个 null 引用的任何属性或方法(例如 length)会导致 NullPointerException。因此,这个检查是必要的,以确保在你的方法中进一步访问 nums1.length 时不会抛出异常。

  2. nums1.length == 0: 这个条件检查数组是否为空,即不包含任何元素。即使 nums1 不是 null(即它是一个有效的数组引用),它也可能是一个空数组,这意味着没有元素可以处理或进行交集操作。如果不检查这个条件,即使方法不会因为 null 引用而失败,它仍然会执行后续的集合操作,但实际上没有任何数据需要处理。

总结来说,这两个条件共同确保了:

  • 安全性:通过检查 null 来防止 NullPointerException
  • 效率:通过确认数组不为空(长度大于0),避免对空数据执行无意义的操作。

202. 快乐数

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

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

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

判断sum是否重复出现就可以使用unordered_set。

非快乐数的特性: 快乐数定义为不断迭代其位数字的平方和最终能够得到1的数字。然而,如果一个数字不是快乐数,这种迭代过程不会以1结束,而是最终会形成一个循环。这个循环包含的数值不包括1,而是一组固定的数字不断重复出现。

1. 两数之和   

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] res = new int[2];
        if (nums == null || nums.length == 0){
            return res;
        }
        // 注意map的各种api
        Map<Integer, Integer> map = new HashMap<>();
        // 在map中寻找是否有匹配的key
        for (int i = 0; i < nums.length; i++) {
            int diff = target - nums[i];
            if (map.containsKey(diff)) {
                res[0] = map.get(diff);
                res[1] = i;
                break;
            }
            // 如果没找到匹配对,就把访问过的元素和下标加入到map中
            map.put(nums[i], i);
        }
        return res;
    }
}

本题其实有四个重点:

1. 为什么会想到用哈希表

使用哈希表主要是因为哈希表提供了快速的查找能力,平均时间复杂度为 O(1)。在这个问题中,需要快速判断数组中是否存在某个特定的数,这个数是当前数与目标值之差。哈希表的高效查找特性使得我们可以在遍历数组的同时,快速查找每个元素的配对元素是否已经出现在之前的遍历中。

2. 哈希表为什么用map

Map 是一种键值对的数据结构,能够让我们将一个值与一个键关联起来,这样我们就可以插入、修改、访问和删除键值对。在 twoSum 函数中使用 Map (在 Java 中通常使用 HashMap)是因为我们需要保存每个数字及其对应的索引位置,以便快速访问和查找。

3. 本题map是用来存什么的

在这个问题中,Map 用来存储数组中的数及其对应的索引。这样做的目的是为了在遍历数组时,能够快速检查目标值与当前数的差是否已经在之前遍历的数中出现过。

4. map中的key和value用来存什么的

twoSum 方法中:

  • key 存储的是 nums 数组中的元素,即数字本身。
  • value 存储的是该元素在数组 nums 中的索引位置。

这种键值对的配置允许我们在遍历数组的过程中,通过简单地计算 target - nums[i] 并查找这个差值是否已经作为一个键存储在 Map 中,从而快速判断是否有两个数的和等于 target。如果差值存在,就意味着我们找到了这样一对数:当前的数 nums[i] 和之前某个数 nums[j],它们的索引分别是 ij,且它们的和正好是 target

通过这种方法,我们不仅优化了问题的时间复杂度(从 O(n^2) 降到 O(n)),也简化了实现,使其更加高效。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值