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

参考

代码随想录

补充

C++中set和map的使用

题目一:LeetCode :242.有效的字母异位词

一、按照自己的思路求解

用两个数组来分别统计两个字符串中的字符出现的次数,然后再比较两个数组是否相等即可,若相等则返回true,否则返回false。

class Solution {
public:
    bool isAnagram(string s, string t) {
        int cnt_s[26] = {0};
        int cnt_t[26] = {0};
        int size_s = s.size();
        for(int i=0;i<size_s;i++)
            cnt_s[s[i]-'a']++;
        int size_t = t.size();
        for(int i=0;i<size_t;i++)
            cnt_t[t[i]-'a']++;
        //比较两个数组
        for(int i=0;i<26;i++)
            if(cnt_s[i] != cnt_t[i])    return false;
        return true;
    }
};

二、参考代码随想录的实现方法

实现思路是一致的,更可以只使用一个数组来统计字符出现的次数,数组初始化全0,遍历第一个字符串用加操作,遍历第二个数组时用减操作,然后判断数组是否全0,若是则返回true,否则返回false。代码实现如下:

class Solution {
public:
    bool isAnagram(string s, string t) {
        int record[26] = {0};
        for (int i = 0; i < s.size(); i++) {
            // 并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
            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) {
                // record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
                return false;
            }
        }
        // record数组所有元素都为零0,说明字符串s和t是字母异位词
        return true;
    }
};

小结

这个题的字符串只包含小写字母,若还有其他字符则会导致字符的ASCII码不连续或者跨度较大,数组的大小也应该做相应的变化,当然也可以使用map来对字符计数。

题目二:LeetCode :349.两个数组的交集

一、按照自己的想法实现

用unordered_set来求解。先遍历一个数组,将数组的数据添加到集合中(同时会去重),然后再遍历另一个数组,每个数在集合中查找,若能查找到,这个数就是公共的数。遍历完成之后还需要对结果去重,因为第二个数组中可能会存在重复的数据。代码如下:

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int>  s;
        vector<int> vec;
        int size1 = nums1.size();
        for(int i=0;i<size1;i++)
            s.insert(nums1[i]);
        int size2 = nums2.size();
        for(int i=0;i<size2;i++)
        {
            auto pos = s.find(nums2[i]);
            if(pos != s.end())
                vec.push_back(nums2[i]);
        }
        //对结果去重
        s.clear();
        for(int i=0;i<vec.size();i++)
            s.insert(vec[i]);
        vec.clear();
        for(auto it = s.begin();it != s.end();it++)
            vec.push_back(*it);
        return vec;
    }
};

二、参考代码随想录的实现方法

代码随想录给出的代码如下:

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());
    }
};

小结

这个题限制了数据的大小:0 <= nums1[i], nums2[i] <= 1000,所以也是可以用数组来实现的,只是占用的空间会大一些。代码如下:

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        int cnt[1005] = {0};
        unordered_set<int> s;
        for(int i:nums1)    cnt[i]++;
        for(int i:nums2)
            if(cnt[i] > 0) s.insert(i);
        return vector<int>(s.begin(),s.end());
    }
};

此外,也可以只用数组实现,如下:

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        bool flag[1000] = {false};
        int size = nums1.size();
        int i;
        vector<int> result;
        for(i = 0; i < size; i++)
            flag[nums1[i]] = true;
        size = nums2.size();
        for(i = 0; i < size; i++)
            if(flag[nums2[i]]){
                result.push_back(nums2[i]);
                flag[nums2[i]] = false;
            }
        return result;
            
    }
};

题目三:LeetCode :202.快乐数

这个题看了之后没什么思路,直接看代码随想录的求解思路。
看了思路之后,发现自己没有理解透题目的意思,题目中有一个很关键的信息:无限循环,也就是说如果和sum出现重合这个数就不是快乐数,这一点很重要。判断一个数是否出现过,那就可以使用哈希表了。自己写的代码如下:

class Solution {
public:
    bool isHappy(int n) {
        unordered_set<int> sum_set;
        int sum = n;
        while(sum != 1)
        {
            int data = sum;
            sum = 0;
            //求平方和
            do
            {
                int tmp = data % 10; //得到最低位
                data /= 10;  //去掉最低位
                sum += tmp * tmp; 
            }while(data);
            if(sum_set.find(sum) != sum_set.end())  return false;
            sum_set.insert(sum);
        }
        return true;
    }
};

代码随想录给出的代码如下:

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;
        }
    }
};

小结

这个题的难点在与理解题目的意思,即如果不是快乐数则会无限循环,这意味着会有重复的数据出现,这是本题的关键,判断一个数据是否出现过就用哈希表。

题目四:LeetCode :1.两数之和

一、按照自己的思路求解

两个数之和num1 + num2 = target,则num1 = target - num2,因此遍历数组,然后查找target-num[i]是否出现过,查找某一个数是否出现过可以用哈希表。代码实现如下:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> mp;
        vector<int> res;
        for(int i=0;i<nums.size();i++)
            mp[nums[i]] = i;
        for(int i=0;i<nums.size();i++)
        {
            auto pos = mp.find(target-nums[i]);
            if(pos != mp.end() && pos->second != i)
            {
                res.push_back(i);
                res.push_back(pos->second);
                break;
            }
        }
        return res;
    }
};

在写代码的时候把键和值弄反了,导致结果错误,所以在使用map的时候一定要明确键和值分别是什么,在这个题中,键是数组中的值,值是其对应的下标,原因是最后要得到的是数组的下标,二这个下标是要通过差值来查找的,所以键应该是数组中的数值。另外,找到之后需要判断这个数是不是本身,比如4+4=8,这种情况是要排除的,即pos->second != i.

二、参考代码随想录的实现方法

代码随想录也是用unordered_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中寻找是否有匹配的key
            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 {};
    }
};

小结

使用map的时候一定要明确键和值分别是什么,否则就会出错。对顺序没有要求时使用unordered_map,效率更高。这题因为同时要保存数组的下标和值,所以不能使用集合。

今日小结

  • 查找某一个元素是否在集合中出现的时候就使用哈希结构(C++中的数组、集合和映射)
  • 要理解什么时候用三种结构中的哪一种合适
  • 对于映射,一定要清楚键和值分别是什么

你可能感兴趣的:(代码随想录训练营,leetcode,算法,数据结构,哈希)