代码随想录Day6 242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和

95 阅读3分钟

Day6 242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和

什么时候使用哈希法,当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。

哈希表理论基础

在C++中,set 和 map 分别提供以下三种数据结构,其底层实现以及优劣如下表所示:

集合底层实现是否有序数值是否可以重复能否更改数值查询效率增删效率
std::set红黑树有序O(log n)O(log n)
std::multiset红黑树有序O(logn)O(logn)
std::unordered_set哈希表无序O(1)O(1)

std::unordered_set底层实现为哈希表,std::set 和std::multiset 的底层实现是红黑树,红黑树是一种平衡二叉搜索树,所以key值是有序的,但key不可以修改,改动key值会导致整棵树的错乱,所以只能删除和增加。

映射底层实现是否有序数值是否可以重复能否更改数值查询效率增删效率
std::map红黑树key有序key不可重复key不可修改O(logn)O(logn)
std::multimap红黑树key有序key可重复key不可修改O(log n)O(log n)
std::unordered_map哈希表key无序key不可重复key不可修改O(1)O(1)

std::unordered_map 底层实现为哈希表,std::map 和std::multimap 的底层实现是红黑树。同理,std::map 和std::multimap 的key也是有序的(这个问题也经常作为面试题,考察对语言容器底层的理解)。

快速判断某个元素是否在集合中时,用哈希表

blog.csdn.net/Huang_JinXi…

242.有效的字母异位词

没想出来哈希表的写法

数组其实是一种简单的哈希表,利用数组进行解答

class Solution {
public:
    bool isAnagram(string s, string t) {
        vector<int> record(26, 0);//vector 初始化
        //int record[26] = {0};
        for(int i = 0; i < s.length(); i++){
            record[(int)s[i] - 'a'] ++;
        }
        for(int i = 0; i < t.length(); i++){
            record[(int)t[i] - 'a'] --;
        }
        for(int i = 0; i < 26; i++){
            if(record[i] > 0 || record[i] < 0){
                //也有可能是负数,即t的长度大于s的长度
                // if(record[i] != 0)
                return false;
            }
        }
        return true;
    }
};

349. 两个数组的交集

初始解法:使用map

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        map<int, int> numMap;
        for(int i = 0; i < nums1.size(); i++){
            numMap[nums1[i]] = i;
        }
        vector<int> ret;
        for(int i = 0; i < nums2.size(); i++){
            map<int, int>::iterator iter = numMap.find(nums2[i]);
            if(iter != numMap.end() && find(ret.begin(),ret.end(), nums2[i]) == ret.end()){
                ret.push_back(nums2[i]);
            }
        }
        return ret;
    }
};

map的创建

find的应用find(ret.begin(),ret.end(), nums2[i])

标程解法:使用set

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

for (int num : nums2)

202. 快乐数

初始解法: 暴力解法

class Solution {
public:
    bool isHappy(int n) {
        int sum = n;
        int target = n;
        int count = 0;
        while(sum != 1){
            count ++;
            target = sum;
            sum = 0;
            while(target > 0){
                int a = target % 10;
                target = target / 10;
                sum += a * a;
            }
            if(count > 100000) return false;
        }
        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;
        }
    }
};

sum会重复出现

set.find(sum)

set.insert(sum)

1. 两数之和

初始解法 map

以前做过好几次,印象比较深

class Solution {
 public:
  vector<int> twoSum(vector<int>& nums, int target) {
    map<int, int> numMap;
    for(int i = 0; i < nums.size(); i++){
        if(numMap.find(target - nums[i]) == numMap.end()){
            numMap[nums[i]] = i;
        }else{
            return vector<int>{i, numMap[target - nums[i]]};
        }
    }
    return vector<int>{};
  }
};

标程 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 {};
    }
};

iter->second

map.insert(pair<int, int>(nums[i], i))