算法训练1-day5

19 阅读3分钟

今天的四道题是哈希表

  1. 242. 有效的字母异位词

题目要求s能构成t,并且所有的字母都要使用一次,这就意味着不仅s与t的长度要一致,s与t的字母种类也一致,且每种字母的个数也相同。

AC代码:

class Solution {
public:
    bool isAnagram(string s, string t) {
        if (s.size() != t.size())
            return false;
        unordered_map<char, int> sCount;
        for (char c : s) {
            sCount[c]++;
        }
        for (char c : t) {
            if (sCount.find(c) == sCount.end() || sCount[c] <= 0) {
                return false;
            }
            sCount[c]--;
        }
        return true;
    }
};

//只针对小写字母,可以使用26大小的数组
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;
    }
};
  1. 349. 两个数组的交集
  • 可以使用nums1_set.find(num) == nums1_set.end()来判断是否已经存在num
  • 也可以直接使用<iterator,bool> insert( const value_type& value );(来源unordered_set::insert)或者<iterator, bool> emplace( Args&&... args );(来源unordered_set::emplace),这两个函数会自动放弃重复的插入操作,并返回false

AC代码:

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> nums1_set;
        for(int num:nums1){
            if(nums1_set.find(num) == nums1_set.end()){
                nums1_set.emplace(num);
            }
        }

        vector<int> ans;
        for(int num:nums2){
            if(nums1_set.find(num) != nums1_set.end()){
                ans.push_back(num);
                nums1_set.erase(num);
            }
        }

        return ans;
    }
};

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());
    }
};
  1. 202. 快乐数

这道题难点在于非快乐数时该如何判断,重点在于非快乐数会无限循环,也就意味着n所变化的数有着重复,因此使用一个哈希表记录n变化的数,若有重复,则不是快乐数。

AC代码:

class Solution {
public:
    bool isHappy(int n) {
        unordered_set<int> n_set;
        while (n_set.find(n) == n_set.end()) {
            n_set.emplace(n);
            n = GetHappyNum(n);
            if (n == 1)
                return true;
        }
        return false;
    }
private:
    int GetHappyNum(int n) {
        int happyNum = 0;
        int num = 0;
        while (n > 0) {
            num = n % 10;
            happyNum += num * num;
            n /= 10;
        }
        return happyNum;
    }
};

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;
        }
    }
};
  1. 1. 两数之和

用unordered_multimap记录每个数的值与对应的下标,然后检查每个数nums[i]是否存在对应的target - nums[i],要注意的一点就是当nums[i] = target/2时,需要判断是否还存在额外的nums[i],如果只有一个满足nums[i] = target/2nums[i],那么是不满足条件的。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_multimap<int, int> numToIndex;
        for (int i = 0; i < nums.size(); ++i) {
            numToIndex.emplace(nums[i], i);
        }
        vector<int> ans(2);
        for (int i = 0; i < nums.size(); ++i) {
            auto it = numToIndex.find(target - nums[i]);
            if (it != numToIndex.end()) {
                // nums[i] = target/2
                if (it->second == i) {
                    if (numToIndex.count(nums[i]) > 1) {
                        auto ranges = numToIndex.equal_range(nums[i]);
                        ans[0] = i;
                        ans[1] = (++ranges.first)->second;
                        break;
                    }
                } else {
                    ans[0] = i;
                    ans[1] = it->second;
                    break;
                }
            }
        }
        return ans;
    }
};

//边遍历边寻找
//对于重复的情况,因为题目保证每种输入只会对应一个答案
//所以此时,这种特殊情况也可以也转化为普通的情况
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 {};
    }
};