代码随想录第五天:哈希表、字母异位、数组交集、快乐数、两数之和

1.哈希表

哈希表是用于快速查找目标的数据结构,有三种:数组、集合和映射。

数组是以下标为索引的哈希结构,通过下标能直接访问对应元素,查找时间复杂度为O(1)。数组数据的最大长度是1000。所以遇到固定长度,数据跨度小的问题可以使用数组解决。

集合在C++中有三种:

根据题目需要使用顺序为unordered_set -> set -> multiset。集合的操作有:find、insert、erase等

映射同样有三种:

根据题目需要使用顺序为unordered_map -> map -> multimap。map存储键值对,可以通过key找到对应value。

2.字母异位

题目链接:. - 力扣(LeetCode)

讲解链接:代码随想录 (programmercarl.com)

视频讲解:学透哈希表,数组使用有技巧!Leetcode:242.有效的字母异位词_哔哩哔哩_bilibili

本体考察两个字符串出现的字母及其数量是否完全相同。所以我们自然想到是否可以统计每一个字母的数量,再将二者对比。而提到查找某个元素是否出现的时候,要立刻想到哈希法。

本体使用哪种哈希结构呢,我们需要统计字母及其数量,所以排除set。再看能不能使用数组,字母一共26个,个数确定,所以可以使用数组表示。26个字母分别代表0-25的数组下标,数组元素表示其出现次数。

我们需要两个数组来对比其是否完全相同,但是还有个方法是第二个字符串的统计可以在同一个数组中做减法。如果最后数组元素全为0,即证明两个字符串是异位的。

代码如下:

bool isAnagram(string s, string t) {
    vector<int> count(26,0);
    for (int i = 0; i < s.length(); ++i) {
        count[s[i] - 'a']++;
    }
    for (int i = 0; i < t.length(); ++i) {
        count[t[i] - 'a']--;
    }
    for (int i = 0; i < 26; ++i) {
        if (count[i] != 0)
            return false;
    }
    return true;
}

tips:如何用下标表示26个字母?a用0表示,因为小写字母在ASCII码上是连续的,后面的字母与a相差多少位,其下标就是多少。所以其他字母的下标是x(任意字母)- 'a'。

2.数组交集

题目链接:. - 力扣(LeetCode)

讲解链接:代码随想录 (programmercarl.com)

视频讲解:学透哈希表,set使用有技巧!Leetcode:349. 两个数组的交集_哔哩哔哩_bilibili

本体最后的结果数组中元素是唯一的,所以我们要判断有没有在两个数组中都出现过的元素。判断元素是否存在立即想到哈希法。

再考虑使用哪种数据结构。本体并不需要返回元素的位置,只需要找到元素即可,所以使用set。且结果数组元素不重复且无序,使用unordered_set。

本体准备两个set。第一个set记录数组1的元素(自动去重),再循环中每次判断数组2的元素是否出现在set1中。如果出现,将它记录到set2中。最后将set2内容转化为数组即可。

代码如下:

vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
    //结果集合
    unordered_set<int> result_set;
    //记录集合,将nums1记录到集合中
    unordered_set<int> record_set(nums1.begin(), nums1.end());
    //将nums2中的每一个元素放到临时变量num中
    for (int num : nums2){
        //unordered_set.find()函数找到目标时会返回指向目标元素的迭代器,
        //否则返回unordered_set.end,表示集合的末尾
        if (record_set.find(num) != record_set.end())
            //集合插入元素
            result_set.insert(num);
    }
    //创建以结果集合内容初始化的容器
    return vector<int>(result_set.begin(),result_set.end());
}

tips:本体涉及一些第一次接触的语法内容,如set的初始化(使用数组),数组的初始化(使用set),判断set是否找到内容,set插入新元素以及for循环的新写法等。

3.快乐数

题目链接:. - 力扣(LeetCode)

讲解链接:代码随想录 (programmercarl.com)

本体最重要的是搞清楚判断逻辑:是快乐数的话改数最后运算会变成1,如果不是的话会陷入循环。所以我们要知道运算过程中该数是否重复出现,因此使用哈希法。

数据结构依然使用set,因为只需要判断是否存在。

此外每个数运算过程建议写成函数方便调用。

代码如下:

int getSum(int num){
    int sum = 0;
    while (num){
        sum += (num % 10) * (num % 10);
        num /= 10;
    }
    return sum;
}

bool isHappy(int n) {
    unordered_set<int> record_set;
    while (1){
        if (getSum(n) == 1)
            return true;
        else{
            n = getSum(n);
            if (record_set.find(n) != record_set.end())
                return false;
            record_set.insert(n);
        }
    }
}

4.两数之和

题目链接:. - 力扣(LeetCode)

讲解链接:代码随想录 (programmercarl.com)

视频讲解:梦开始的地方,Leetcode:1.两数之和,学透哈希表,map使用有技巧!_哔哩哔哩_bilibili

本题判断一个数组中是否存在和为目标值的两个元素,并返回他们的下标。目标是查找,所以使用哈希法。

再判断使用什么数据结构,本体不但需要查找元素,还要返回下标。所以不能使用set。另外数组内元素范围不知道,所以不方便使用数组。因此本体使用map。考虑到结果集无序且不重复,使用unordered_map。

遍历数组,每次在map中查找是否存在与当前元素和为目标值的元素,是则返回下标(循环中的i与map中key对应的value),否则记录元素及其下标分别为key-value。

代码如下:

vector<int> twoSum(vector<int>& nums, int target) {
    unordered_map<int, int> record_map;
    for (int i = 0 ; i < nums.size() ; i++) {
        auto iter = record_map.find(target - nums[i]);
        if (iter != record_map.end())
            return {iter->second, i};
        record_map.insert(pair<int, int>(nums[i], i));
    }
    return {};
}

tips:本体涉及map相关语法,包括初始化与插入键值对的语法。另外包含c++迭代器的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值