训练营第五天|242. 有效的字母异位词|349. 两个数组的交集|202. 快乐数|1. 两数之和

242. 有效的字母异位词

利用数组形成哈希表(对于固定长度结构的遍历)

因为字母的长度的是固定的,所以可以利用数组的索引当成hash表的键。

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 < 26; i++){
            if(record[i] != 0){
                return false;
            }
        }
        return true;
    }
};

定义一个数组叫做record用来上记录字符串s里字符出现的次数。

需要把字符映射到数组也就是哈希表的索引下标上,因为字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下标0,相应的字符z映射为下标25。

再遍历 字符串s的时候,只需要将 s[i] - ‘a’ 所在的元素做+1 操作即可,并不需要记住字符a的ASCII,只要求出一个相对数值就可以了。 这样就将字符串s中字符出现的次数,统计出来了。

那看一下如何检查字符串t中是否出现了这些字符,同样在遍历字符串t的时候,对t中出现的字符映射哈希表索引上的数值再做-1的操作。

那么最后检查一下,record数组如果有的元素不为零0,说明字符串s和t一定是谁多了字符或者谁少了字符,return false。

最后如果record数组所有元素都为零0,说明字符串s和t是字母异位词,return true。

时间复杂度为O(n),空间上因为定义是的一个常量大小的辅助数组,所以空间复杂度为O(1)。

349. 两个数组的交集

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> result_set;
        //利用数组形成hash表
        int hash[1005] = {0};

        //foreach循环了解 num是指指向nums1中各元素的指针
        //与fori的区别
        for(int num : nums1){
            hash[num] = 1;
        }

        for(int num: nums2){
            if(hash[num] == 1){
                result_set.insert(num);
            }
        }
	   //输出result_set
        return vector<int>(result_set.begin(), result_set.end());
    }
};

拓展

那有同学可能问了,遇到哈希问题我直接都用set不就得了,用什么数组啊。

直接使用set 不仅占用空间比数组大,而且速度要比数组慢,set把数值映射到key上都要做hash计算的。

不要小瞧 这个耗时,在数据量大的情况,差距是很明显的。

202. 快乐数

//死循环判断

//过关思维

//进入无限循环的条件

//求和过程:取数值各位的单数操作

/*
 * @lc app=leetcode.cn id=202 lang=cpp
 *
 * [202] 快乐数
 */

// @lc code=start
class Solution {
public:

    int getSum(int n){
        int sum = 0;
        while (n)
        {
            /* code */
            //取模运算取最后一位
            sum += (n % 10) * (n % 10);
            //除以10去掉最后一位
            n /= 10;
        }
        return sum;
        
    }

    bool isHappy(int n) {
        //判断sum是否重复出现过,出现过则是无限循环跳出
        //否则一直寻找到出现1为止
        unordered_set<int> result;
        
        
        while(1){
            int sum = getSum(n);
            if(sum == 1){
                return true;
            }

            //遍历一下result,如果已在之前出现证明已进入无限循环
            if(result.find(sum) != set.end()){
                return false;
            }else{
                result.insert(sum);
            }
            //正常插入的话就继续进行快乐数的判断
            //也是过关思维的一种体现,先将否和跳出的情况放在之前判断
            n = sum;          
        }
    }
};
// @lc code=end

题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现,这对解题很重要!

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

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

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

1. 两数之和

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

再来看一下使用数组和set来做哈希法的局限。

  • 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
  • set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用。

此时就要选择另一种数据结构:map ,map是一种key value的存储结构,可以用key保存数值,用value在保存数值所在的下标。

接下来需要明确两点:

  • map用来做什么
  • map中key和value分别表示什么

map目的用来存放我们访问过的元素,因为遍历数组的时候,需要记录我们之前遍历过哪些元素和对应的下标,这样才能找到与当前元素相匹配的(也就是相加等于target)

接下来是map中key和value分别表示什么。

这道题 我们需要 给出一个元素,判断这个元素是否出现过,如果出现过,返回这个元素的下标。

那么判断元素是否出现,这个元素就要作为key,所以数组中的元素作为key,有key对应的就是value,value用来存下标。

所以 map中的存储结构为 {key:数据元素,value:数组元素对应的下标}。

在遍历数组的时候,只需要向map去查询是否有和目前遍历元素匹配的数值,如果有,就找到的匹配对,如果没有,就把目前遍历的元素放进map中,因为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++){
            //遍历元素,并在map中寻找之前是否有元素匹配
            auto iter = map.find(target - nums[i]);
            //如果找到的话,返回两个元素的下标
            if(iter != map.end()){
                return {iter->second, i};
            }
            //如果没找到,将该元素和索引存入map,证明已访问过
            map.insert(pair<int, int>(nums[i], i));
        }

        return {};

    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值