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

15. 有效的字母异位

C++:

这里使用了哈希表的方法

先将传入的两个字符串的每一项读取到各自的数组中,然后判断数组的各项数值是否相等,如果相等就是有效的字母异位,不相等就不是

不过!!!代码随想录给出的代码有一点很值得学习一下:先将第一个字符串的字母统计到一个数组中,然后,在统计第二个字符串的时候,在原来的那个数组中做减法,那样只需要一个数组,在之后只需要统计,数组里是否有比0小的数,只要有就输出false!非常巧啊!

class Solution {
public:
    bool isAnagram(string s, string t) {
        int record[26] = {0};

        for (int i = 0; i < s.size(); i++){
            record[s[i] - 'a']++;
        }
        for (int i = 0; i < t.size(); i++){
            record[t[i] - 'a']--;
        }

        for (int i = 0; i < sizeof(record)/sizeof(record[0]); i++){
            if (record[i] != 0){
                return false;
            }
        }
        return true;
    }
};

16. 两个数组的交集

C++:

这个题触碰到了我的一个大的知识上的漏洞,C++的容器和迭代器那部分的内容没学习呢,得补一补了!

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> result_set; // 存放结果,之所以用set是为了给结果集去重
        unordered_set<int> nums_set(nums1.begin(), nums1.end());
        for (int num : nums2) {
            // 发现nums2的元素 在nums_set里又出现过
            if (nums_set.find(num) != nums_set.end()) {
                result_set.insert(num);
            }
        }
        return vector<int>(result_set.begin(), result_set.end());
    }
};
  1. intersection 函数中,创建了一个 unordered_set<int> 类型的 result_set 对象,用于存放结果。使用 unordered_set 是为了避免结果集中出现重复的元素。

  2. 创建了一个 unordered_set<int> 类型的 nums_set 对象,并使用 nums1 容器的迭代器范围初始化它。这样做的目的是将 nums1 中的元素放入 nums_set 中,以便快速查找。

  3. 使用 for 循环遍历 nums2 容器中的每个元素,并对每个元素执行以下操作:

    a. 使用 nums_set.find(num)nums_set 中查找当前元素 num

    b. 如果 find 操作返回的迭代器不等于 nums_set.end(),即找到了与 nums2 中当前元素相等的元素,则将当前元素插入到 result_set 中。

    注:

    1. result_set.begin():这是 unordered_set 类的成员函数,返回一个指向 result_set 集合中第一个元素的迭代器。
    2. result_set.end():这也是 unordered_set 类的成员函数,返回一个指向 result_set 集合中最后一个元素之后位置的迭代器。
    3. vector<int>(result_set.begin(), result_set.end()):这是 vector 类的构造函数,它接受两个迭代器参数,表示一个范围,并将该范围内的元素复制到一个新的 vector<int> 对象中。
      • result_set.begin() 是范围的起始迭代器,指向 result_set 集合中第一个元素。
      • result_set.end() 是范围的结束迭代器,指向 result_set 集合中最后一个元素之后的位置。
  4. 返回一个新的 vector<int> 对象,该对象包含了 result_set 中的所有元素。这是通过使用 vector 类的迭代器范围构造函数实现的。

按照代码随想录上的后记,立扣改了题目描述和后台测试数据,增添了数值的范围,所以使用数组也是可以的,那么就可以对上述的代码进行简单的修改

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> result_set; // 存放结果,之所以用set是为了给结果集去重
        int hash[1005] = {0}; // 默认数值为0
        for (int num : nums1) { // nums1中出现的字母在hash数组中做记录
            hash[num] = 1;
        }
        for (int num : nums2) { // nums2中出现话,result记录
            if (hash[num] == 1) {
                result_set.insert(num);
            }
        }
        return vector<int>(result_set.begin(), result_set.end());
    }
};

17. 快乐数

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

因为可能要无限循环,得到特别多的数,我们要在这特别多的数中间找到快速判断一个元素是否出现过,这个时候,就想到了哈希表

那么重点在于,如何去求解传入参数n的各位平方之和呢?

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

class Solution {
public:
    // 取数值各个位上的单数之和
    int getSum(int n) {
        int sum = 0;
        while (n) {
            sum += (n % 10) * (n % 10);
            n /= 10;
        }
        return sum;
    }
    bool isHappy(int n) {
        unordered_set<int> set;
        while(1) {
            int sum = getSum(n);
            if (sum == 1) {
                return true;
            }
            // 如果这个sum曾经出现过,说明已经陷入了无限循环了,立刻return false
            if (set.find(sum) != set.end()) {
                return false;
            } else {
                set.insert(sum);
            }
            n = sum;
        }
    }
};

在这里需要重点说一下,这个 set.find(sum) != set.end() 这是一个条件表达式,用于判断 set.find(sum) 返回的迭代器是否等于 set.end(),即是否找到了与 sum 相等的元素。

  • 如果 set.find(sum) 返回的迭代器不等于 set.end(),说明在 set 中找到了与 sum 相等的元素,条件成立,表达式的值为 true
  • 如果 set.find(sum) 返回的迭代器等于 set.end(),说明在 set 中未找到与 sum 相等的元素,条件不成立,表达式的值为 false

18. 两数之和

242. 有效的字母异位词 这道题目是用数组作为哈希表来解决哈希问题,349. 两个数组的交集 这道题目是通过set作为哈希表来解决哈希问题。

什么时候使用哈希法,当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。

本题呢,我就需要一个集合来存放我们遍历过的元素,然后在遍历数组的时候去询问这个集合,某元素是否遍历过,也就是 是否出现在这个集合。那么我们就应该想到使用哈希法了。

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

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {

        std::unordered_map<int,int> map;

        for (int i = 0; i < nums.size(); i++){

            auto iter = map.find(target - nums[i]);

            if (iter != map.end()){
                return {iter->second, i};
            }
            map.insert(pair<int, int>(nums[i], i));
        }
        return {};
    }
};
  • 首先需要学习的是map数据结构的创建方式 std::unordered_map<int,int> map;

  • auto iter = map.find(target - nums[i]); 中的 auto 的含义:

    • 关键字 auto 被用于声明一个变量 iter,其类型是根据等号右侧的表达式自动推导得出的。在这种情况下,map.find(target - nums[i]) 返回的是一个迭代器,其类型是 std::unordered_map<int, int>::iterator(或者是 std::unordered_map<int, int>::const_iterator)。因此,使用 auto 关键字可以让编译器根据返回类型自动推导出 iter 的类型,而不必手动指定迭代器的类型。
    • 使用 auto 关键字的好处是使代码更简洁,减少了重复的类型声明,同时也使代码更具灵活性和可读性。当我们不关心迭代器的具体类型时,使用 auto 关键字可以更加简洁地编写代码。
  • map.find(target - nums[i]) 返回的是一个迭代器,用于指向 std::unordered_map 中的键值对。具体来说,它是 std::unordered_map<int, int>::iterator 类型的迭代器,或者如果是在常量对象上调用的,则为 std::unordered_map<int, int>::const_iterator 类型的迭代器。

    迭代器是一种用于访问容器中元素的对象,它可以指向容器中的任意一个元素,并且可以通过迭代器来访问该元素的值或进行修改。在这种情况下,map.find(target - nums[i]) 返回的迭代器指向了键值为 target - nums[i] 的元素(如果存在的话),否则返回 map.end(),表示未找到。

    因此,map.find(target - nums[i]) 返回的是一个迭代器,用于在 std::unordered_map<int, int> 中查找键值为 target - nums[i] 的元素。

  • iter->second 是通过迭代器 iter 访问键值对中的值部分的语法。在 std::unordered_map 中,每个键值对都有两部分:键和值。键存储在 first 成员中,而值存储在 second 成员中。

  • pair<int, int> 是一个 std::pair 类模板的实例化,用于表示包含两个值的有序对。具体来说,pair<int, int> 表示包含两个整数类型的值的有序对。

    map.insert(pair<int, int>(nums[i], i)); 中,它表示要将一个有序对插入到 std::unordered_map<int, int> 类型的 map 中。这个有序对的第一个值是 nums[i],第二个值是 i,即将当前数组元素 nums[i] 作为键,将其索引 i 作为值,插入到 map 中。

  • 17
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值