记录算法Day5

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

哈希理论基础

https://programmercarl.com/%E5%93%88%E5%B8%8C%E8%A1%A8%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html

收获:

当问题转换为判断一个元素是否再一个集合里时优先考虑哈希

Leetcode 242.有效的字母异位词

题目链接 LCR 032. 有效的字母异位词
文章链接 https://programmercarl.com/0242.%E6%9C%89%E6%95%88%E7%9A%84%E5%AD%97%E6%AF%8D%E5%BC%82%E4%BD%8D%E8%AF%8D.html
视频链接 https://www.bilibili.com/video/BV1YG411p7BA

思路

暴力可以做,但是主要是练一下哈希。这道题可以把‘a’-'z’映射成0-25即可,26的长度直接用数组存就好了,定义两个数组(也可以定义一个),分别记录每个串中的每个字符出现次数,再判断两个数组的每个值是否相等

代码

 class Solution {

public:

    bool isAnagram(string s, string t) {

        vector<int> data1(26);//26个英文字母,只需要开辟26个数组单元就可以了

        vector<int> data2(26);

        if(s.length()!=t.length()){

            return false;

        }

        for(char c:s){

            data1[c-'a']++;//‘a’从0开始存储

        }

        for(char c:t){

            data2[c-'a']++;

        }

        for(int i=0;i<26;i++){

            if(data1[i]!=data2[i]){

                return false;

            }

        }

        return true;

    }

};

Leetcode 349 两个数组的交集

题目链接 349. 两个数组的交集
文章链接 https://programmercarl.com/0349.%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4%BA%A4%E9%9B%86.html
视频链接 https://www.bilibili.com/video/BV1ba411S7wu

思路

和上道题思路差不多,定义一个record数组存储在nums1数组现过的数字(对应下标的值更新为1),再遍历nums2,把值为1的下标(代表在nums2中出现且在nums1中出现)用另一个数组存储起来。因为这道题给出了数组的值的范围为0-1000,所以可以用数组存储。如果没给出长度,那可以用集合来存,要存的内容不能有重复,而且不需要有顺序,所以这里用到的容器unordered_set的效率是最高的(底层实现为哈希)。

代码

  • 数组
class Solution {

public:

    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {

        vector<int> result(1001,0);//结果数组

        vector<int> record(1001,0);//记录数组

        int index = 0;

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

            record[nums1[i]] = 1;//把nums1中出现过的数更新为1,代表已经出现过

        }

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

            if(record[nums2[i]]==1){//在nums2中出现同时也在nums1中出现

                result[index++] = nums2[i];//存下

                record[nums2[i]] = 0;//防止重复的元素进入

            }

        }

        result.resize(index);

        return result;

    }

};
  • 集合(unordered_set)
class Solution {

public:

    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {

        unordered_set<int> result;

        unordered_set<int> data(nums1.begin(),nums1.end());//把nums1的元素全都存入unordered_set

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

            if(data.find(nums2[i])!=data.end()){

                result.insert(nums2[i]);

            }

        }

        vector<int> res(result.begin(),result.end());

        return res;

    }

};

Leetcode 202 快乐数

题目链接 202. 快乐数
文章链接 https://programmercarl.com/0202.%E5%BF%AB%E4%B9%90%E6%95%B0.html

思路

举个例子:37
在这里插入图片描述

发现不是快乐数的数会无限的循环,有点像反复经过一个轮次,当一个数已经出现过时,就说明开始了新的循环轮次,所以这道题就是判断一个数是否已经出现在先前出现的集合中,用哈希来做,长度不固定,可以没有顺序,且元素不重复,选择unordered_set,当每次计算后的每个数位平方和的数没出现过,就插入集合,出现过就不是快乐数

代码

class Solution {

public:

    int calculate(int n){

        int sum = 0;

        while(n){

            sum += (n%10)*(n%10);

            n = n/10;

        }//循环结束时,n为个位数

        sum += n*n;

        return sum;

    }//计算每个数各个数位的平方和

    bool isHappy(int n) {

        unordered_set<int> data;

        int res;

		data.insert(n);

        while(n!=1){

            res = calculate(n);

            if(data.find(res)==data.end()){

                data.insert(res);//集合中没有这个元素,则插入

            }else{

                return false;//如果元素出现过,就说明这个数是每个轮次的开始,要无限循环下去了,不可能是快乐数

            }

            n = res;//每次更新n的值

        }

        return true;

    }

};

Leetcode 1.两数之和

题目链接 1. 两数之和
文章链接 https://programmercarl.com/0001.%E4%B8%A4%E6%95%B0%E4%B9%8B%E5%92%8C.html

思路

看完题解之后,发现我的做法时间复杂度有点高了,原因是我用的multimap来存储,其底层使用红黑树实现,查询和增加删除的时间复杂度都是O(logn),所以我写的时间复杂度是(nlogn)。先写一下我的思路,这道题我翻译成判断target-nums[i]的值是否在集合内,用哈希做,所以我就要存数组所有的值,要求下标,所以要存的内容是(nums[i],i),故选择用map来存,因为我是先存,所以就有key值一样的情况,就想到了multimap来存储。遍历这个容器,如果target-nums[i]在容器内就返回下标,要注意需要加上下标不等的条件来应对键值相等的情况。

再说说题解的,题解用的unordered_map,其底层是用的哈希实现,查询和增加删除的时间复杂度都是O(1),代码总的时间复杂度为O(n)。遍历nums,一个一个存,用后面的数做nums[i];如果target-nums[i]在之前的集合已经出现过,返回下标。这就避免了键值相等存不进去的情况

  • multimap
class Solution {

public:

    vector<int> twoSum(vector<int>& nums, int target) {

        multimap<int,int> data;

        vector<int> result(2,0);

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

            data.insert(make_pair(nums[i],i));

        }//先全部存入

        for(auto it=data.begin();it!=data.end();it++){

            result[0] = it->second;

            //cout<<result[0]<<" ";

            auto temp = data.find(target-it->first);

            if(temp!=data.end()&&(it->second)!=(temp->second)){

                result[1] = temp->second;

                //cout<<result[1]<<endl;

                break;

            }

        }

        return result;

    }

};
  • unordered_map
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map <int,int> map;
        vector<int> result(2);
        for(int i = 0; i < nums.size(); i++) {
            // 遍历当前元素,并在map中寻找是否有匹配的key
            auto temp = map.find(target - nums[i]); 
            if(temp != map.end()) {
	            result[0] = temp->second;
	            result[1] = i;
                return result;
            }
            // 如果没找到匹配对,就把访问过的元素和下标加入到map中
            map.insert(make_pair(nums[i], i)); 
        }
        return {};
    }
};
  • 28
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值