代码训练营第6天打卡 | 哈希表 242. 有效的字母易位词 349. 两个数组的交集 202.快乐数 1. 两数之和

哈希表理论基础

哈希表(Hash Table一般用来判断一个元素是否出现在集合中)。

解决哈希碰撞的方法:

一 开放寻址法

  1. 线性探测法:当发生冲突时,线性的向后面找到下一个bucket存放数值
  2. 二次探测法:就是在线性探测的基础上,加上平方的位置偏移量。(相对于线性探测,二次探测通过使用平方增量序列,减少了因简单线性探查可能导致的“聚集”现象,即连续冲突的元素倾向于分布在一条直线上,这有助于提高哈希表的利用率和查找效率。
    由于探查序列是非线性的,它能够更好地利用哈希表中的空槽位,特别是在哈希表负载适中且冲突分布均匀的情况下。)

二 链地址法

  1. 在哈希值碰撞处的索引,使用链表(链表也可以使用红黑树,平衡二叉搜索树等数据结构替代)

C++中的哈希表数据结果

对于哈希表,常使用的数据结果就三种:

  • 数组
  • set (集合)
  • map (映射)

C++中的set数据结构

名称底层实现key是否有序插入\查找 时间复杂度
set红黑树有序O(logn)
multiset红黑树有序O(logn)
unordered_set哈希表无序O(1)

其中multiset是允许用重复的元素的。(map的数据结构也是这三种类型)

相关知识:红黑树

242. 有效的字母易位词

题目:给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。

示例 1:

输入: s = “anagram”, t = “nagaram”
输出: true
示例 2:

输入: s = “rat”, t = “car”
输出: false

思路:

本题使用能包含重复元素的multi set即可

代码:

class Solution {
public:
    bool isAnagram(string s, string t) {
        if(s.length() != t.length()) return false;

        multiset<char> m1;
        for(int i = 0; i < s.length(); i++) {
            m1.insert(s[i]);
        }

        multiset<char>::iterator tmp = m1.end();
        for(int j = 0; j < t.length(); j++) {
            tmp = m1.find(t[j]);
            if(tmp != m1.end()) {
                m1.erase(tmp);
            }
        }

        if(m1.empty()) return 1;
        return 0;

    }
};

349. 两个数组的交集

题目:

给定两个数组 nums1 和 nums2 ,返回 它们的
交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。

思路:

使用unordered_set即可。注意将vector转换为unordered_set时,可以使用unordered_set的构造函数,直接将vector.begin()和vector.end()两个构造器传入,构造出unordered_set。反之转换,同理。

代码:

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        // 要点:熟悉unordered_set的构建函数
        // 和如何把unordered_set转换为vector
        unordered_set<int> resultSet;
        unordered_set<int> set1(nums1.begin(), nums1.end());

        for(int num: nums2) {
            if(set1.find(num) != set1.end()) {
                resultSet.insert(num);
            }
        }

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

202.快乐数

题目:

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

示例 1:

输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

示例 2:

输入:n = 2
输出:false

思路:

这题要想清楚,先将快乐数的技术结构都存在unordered_set里面,只要有一次计算的值在该set里出现了,就说明该数不可能是快乐数。它会一直循环的计算下去。然后一直计算,直到遇到满足条件的1。

但是这题利用哈希表,就是为了找出在快乐数的计算结果组成的一条链表之中,有没有出现环(即相同的结果出现在历史的计算结果中,因此为了节省数据空间,使用快慢指针的方法即可。)

时间复杂度: 每次计算 n 的快乐数时,需要的复杂度为 O(logn), 计算下一回的时间复杂度为 O(lognlogn), 所以最后整个题目的时间复杂度为 O(logn)

代码:

class Solution {
public:
    int bitSquareSum(int n) {
        int sum = 0;
        while(n > 0)
        {
            int bit = n % 10;
            sum += bit * bit;
            n = n / 10;
        }
        return sum;
    }
    
    bool isHappy(int n) {
        int slow = n, fast = n;
        do{
            slow = bitSquareSum(slow);
            fast = bitSquareSum(fast);
            fast = bitSquareSum(fast);
        }while(slow != fast);
        
        return slow == 1;
    }
};

1. 两数之和

题目:

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

思路:

可以使用哈希表的map结构,For循环依次将数组的元素i,判断(target - i)是否存在于map中。若存在,则返回该两个数的坐标即可,若不存在,将[key: nums[i], value: i] 存入map中。注意存入unordered_map m的代码操作,直接用 m[ nums[i] ] = i; 即可

时间复杂度:O(n)

代码:

class Solution {
public:
vector twoSum(vector& nums, int target) {

    unordered_map<int, int> um;
    for(int i = 0; i < nums.size(); i++) {
        if(um.find(target-nums[i]) != um.end()) {
            return {i, um[target-nums[i]]};
        }
        um[nums[i]] = i;
    }

    return {};


}

};

  • 25
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值