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

文章介绍了如何使用map数据结构解决字母异位词问题,通过比较两个字符串中字符及其出现次数来判断是否为异位词。同时讲述了处理数组交集问题的不同方法,包括用set避免重复元素和使用快慢指针检测循环。最后提到快速找到两个数之和的方法,利用map存储元素及其索引。
摘要由CSDN通过智能技术生成

242.有效的字母异位词

  • 题目链接242.有效的字母异位词
  • 独立思路:用map表记录字符串s中出现过的字母及其出现次数。再遍历字符串t中的每个字符x,若x存在于mp中且mp[x]>0,则将mp[x]--。若二者为同字母异序词,则最终mp会全为0
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

(另解:先排序再return s==t。比较简单,不写了)

//想法:新建map表,key值记录字母,value值记录字母出现的次数,如果两个字符串的key、value值完全一样
//则为同字母异序词
class Solution {
public:
    bool isAnagram(string s, string t) {
        map<char, int> mp;
        int n1 = s.size();
        int n2 = t.size();
        if(n1 != n2)
            return false;

        for(int i = 0; i < n1; i++){	//遍历字符串s
            mp[s[i]]++;
        }
        for(int i = 0; i < n2; i++){	//遍历字符串t
            if(mp.find(t[i]) != mp.end() && mp[t[i]] > 0)
                mp[t[i]]--;
            else
                return false;
        }
        return true;
    }
};

//同种思路,更简洁的版本
class Solution {
public:
    bool isAnagram(string s, string t) {
        map<char, int> mp;
        if(s.size() != t.size())
            return false;

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

        for(const auto &x : mp)		//检查mp是否全空了
            if(x.second != 0)
                return false;

        return true;
    }
};

349. 两个数组的交集

  • 题目链接349. 两个数组的交集 
  • 独立思路:遍历nums1,用set记录其中的元素(方便用find)。再遍历nums2,若其中元素存在于set,则存进vector类型的ans
  • 问题(已解决):用vector类型存储数组,会存到重复的元素!比如nums[]中前后出现了多次的'2'这个元素,2也存在于visited中,则2会被多次存入ans数组。

解决方法:ans也用set类型存储,这样不会存储重复的元素。最后再转换为vector数组并返回

  • 时间复杂度:O(m+n)
  • 空间复杂度:O(m+n)
class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        //vector<int> ans; 不能用vector类型存储!不然会存入重复元素
        unordered_set<int> ans;
        unordered_set<int> visited(nums1.begin(), nums1.end());    
        //记录nums1中出现过的元素,且只存储一次(set不存重复值)
        
        for(int num : nums2){
            if(visited.find(num) != visited.end())
                ans.insert(num);
        }

        return vector<int> (ans.begin(), ans.end());
    }
};

  • 独立思路2(先排序、再双指针):nums1和nums2先排序,再逐个元素比较。相等则加入ans,且两个指针均右移,否则小的那个指针移动
  • 问题(已解决):一开始把排序写成nums1.sort(),结果编译出错了。忘记了vector类型的排序是sort(nums.begin(), nums.end())
  • 时间复杂度:O(nlog2n+mlog2m)
  • 空间复杂度:O(log2n+log2m)
//想法2:先排序再比较
class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        sort(nums1.begin(), nums1.end());
        sort(nums2.begin(), nums2.end());
        int n1 = nums1.size();
        int n2 = nums2.size();
        unordered_set<int> ans;

        int i = 0, j = 0;
        while(i < n1 && j < n2){
            if(nums1[i] == nums2[j]){
                ans.insert(nums1[i]);
                i++; j++;
            }else if(nums1[i] < nums2[j]){
                i++;
            }else{
                j++;
            }
        }
        return vector<int>(ans.begin(), ans.end());
    }
};

202. 快乐数

  • 题目链接202. 快乐数
  • 独立思路:❌ 没想出来,明天回来做。重点要从数学意义上理解, 计算正整数是否为开心数的过程不可能到无限大,只会有两种情况:① 是开心数 ②进入循环
  • 官方题解1:用哈希表记录每个数的squareSum值,当该squareSum值没有在哈希表中出现过,则继续求其squareSum值,直到①出现过 ②最终squareSum为1,跳出循环。判断最终只是否为1即可
  • 时间复杂度:O(logn)
  • 空间复杂度:O(logn)
  1. 位数运算:对于一个数字 n,每次计算平方和涉及的操作次数与其位数成正比。位数可以近似表示为 log(n),因为每增加一位,数字大小增加一个数量级。
  2. 循环检测:理论上,这个过程可能会持续很长时间,但实际上,对于任何数字,要么最终达到1,要么很快进入一个已知的循环。这个循环的大小是固定的,因此这部分的时间复杂度可以被认为是常数时间,即 O(1)
class Solution {
public:
    int getSum(int n){
        int sum = 0;
        while(n > 0){
            int digit = n%10;       //取最低位
            sum += digit*digit;
            n = n/10;       //n向右移1位(舍掉了最低位)
        }
        return sum;
    }

    bool isHappy(int n) {
        unordered_set<int> visited;
        while(n != 1 && visited.find(n) == visited.end()){  //n≠1且未在哈希表中出现过
            visited.insert(n);  
            n = getSum(n);
        }
        return n == 1;
    }
};

  • 官方题解2:用快慢指针判断是否有循环,有循环时slow==fast!=1,无循环时slow==fast==1
  • 时间复杂度:O(logn)
  • 空间复杂度:O(1)
//解法2:快慢指针
class Solution{
public:
    int getSquareSum(int n){
        int sum = 0;
        while(n > 0){
            int digit = n%10;
            sum += digit * digit;
            n = n/10;
        }
        return sum;
    }

    bool isHappy(int n){
        int slow = n;
        int fast = n;
        do{
            slow = getSquareSum(slow);
            fast = getSquareSum(fast);
            fast = getSquareSum(fast);
        }while(slow != fast);   //slow=fast情况:①最终值为1 ②slow与fast碰到了(循环)

        return slow == 1; 
    }
};

1.两数之和

  • 题目链接1.两数之和
  • 独立思路:❌ 没想出来,map表的运用不够熟练
  • 官方题解:用map表,first值存元素值,second值存下标。懂了!
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)
class Solution{
    public:
    vector<int> twoSum (vector<int>& nums, int target){
        map<int, int> m;
        int x;
        for(int i = 0; i < nums.size(); i++){
            x = target-nums[i];
            auto pos = m.find(x);    //map的查找函数是查key值,所以要把具体数值当作key、下标当value存进去
            if(pos != m.end()){ //哈希表mapm中存在key值为x的元素
                return{(*pos).second, i};
            }
            m[nums[i]] = i;
        }
        return {};
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值