六月集训打卡Day7---【哈希】

前言

        来自 英雄哪里出来 的一个 免费 集训,每天 5 5 5 点打卡学习算法(我是为了卷吗,主要是想早起 😏),希望能坚持下去。这里用来复盘每天都的打卡题目。
       今日份知识点:哈希
        xxxxx。

一、题目

题目难度
442. 数组中重复的数据⭐️
2068. 检查两个字符串是否几乎相等⭐️
2283. 判断一个数的数字计数是否等于数位的值⭐️
884. 两句话中的不常见单词⭐️

二、算法思路

1、数组中重复的数据

        (1)计数数组: 建一个计数数组, 遍历一遍数组, 记录每个元素的出现次数, 之后再遍历一遍计数数组, 把出现次数等于 2 的元素取出来.
        时间复杂度: O ( 2 n ) O(2n) O(2n)

class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
        vector<int> cnt(100010);
        for (int i = 0; i < nums.size(); ++ i) {
             ++ cnt[nums[i]];
        }
        vector<int> ret;
        for (int i = 0; i < cnt.size(); ++ i) {
            if (cnt[i] == 2) {
                ret.push_back(i);
            }
        }
        return ret;
    }
};

        (2)原地哈希: 由于题目中给出数组的元素只会出现 1 次或者 2 次, 所以我们可以采用取反作为标记, 记录元素 n u m s [ i ] nums[i] nums[i] 是否出现过. 对于每一个 n u m s [ i ] nums[i] nums[i] 我们将其映射到下标 n u m s [ i ] − 1 nums[i]-1 nums[i]1 的位置去. 随后遍历数组, 如果 n u m s [ i ] nums[i] nums[i] 是正数,那么说明 i + 1 i+1 i+1 这个数在已遍历的元素中没出现过,那么将下标为 n u m s [ i ] − 1 nums[i]-1 nums[i]1 的元素取反,表示已经出现过一次了;如果是负数,那么说明该元素已经出现过一次了,那么我们将其放进答案数组中。
        注意:因为元素可能是负数,所以在取下标的时候,需要取绝对值。
        时间复杂度: O ( n ) O(n) O(n)

class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
        int n = nums.size();
        vector<int> ret;
        for (int i = 0; i < n; ++ i) {
            int t = nums[i];
            if (nums[abs(t) - 1] < 0) {
                ret.emplace_back(abs(t));
            }
            nums[abs(t) - 1] *= -1;
        }
        return ret;
    }
};

2、检查两个字符串是否几乎相等

        (1)计数数组:建两个长度为 26 的计数数组,分别遍历两个字符串,记录每一个字符串中每一个字符出现的频率,最后遍历一遍计数组,如果频率之差超过 3,那么返回 false,否则返回 true。xxxxxxx
        时间复杂度: O ( 2 ∗ n + 26 ) O(2*n+26) O(2n+26)

class Solution {
public:
    bool checkAlmostEquivalent(string word1, string word2) {
        vector<int> cnt1(26), cnt2(26);
        for (auto x: word1) {
            ++ cnt1[x - 'a'];
        }
        for (auto x: word2) {
            ++ cnt2[x - 'a'];
        }
        for (int i = 0; i < cnt1.size(); ++ i) {
            if (abs(cnt1[i] - cnt2[i]) > 3) 
                return false;
        }
        return true;
    }
};

        (2)优化空间:遍历第一个字符串时,对计数数组 +1;遍历第二个字符串时,对计数数组 -1;最后遍历计数数组,如果频数差大于 3,返回 false,否则返回 true。

class Solution {
public:
    bool checkAlmostEquivalent(string word1, string word2) {
        vector<int> cnt(26);
        for (auto x: word1) {
            ++ cnt[x - 'a'];
        }
        for (auto x: word2) {
            -- cnt[x - 'a'];
        }
        for (int i = 0; i < cnt.size(); ++ i) {
            if (abs(cnt[i]) > 3) 
                return false;
        }
        return true;
    }
};

3、判断一个数的数字计数是否等于数位的值

        (1)一个计数数组,记录字符串中每个字符出现的次数,(将字符 i i i 映射到 i − 0 i-0 i0 的下标计数数组中,最后遍历一遍计数数组,如果发现不符合题目要求即返回 false,最后返回 true。
        时间复杂度: O ( 2 n ) O(2n) O(2n)

class Solution {
public:
    bool digitCount(string num) {
        int n = num.size();
        vector<int> cnt(10);
        for (int i = 0; i < n; ++ i) {
            ++ cnt[num[i] - '0'];
        }
        for (int i = 0; i < n; ++ i) {
            if (cnt[i] != num[i] - '0')
                return false;
        }
        return true;
    }
};

4、两句话中的不常见单词

        (1)将 s1 和 s2 拼接起来,把每个单词切分出来,统计出现的频数。如果出现的频数为 1,那么说明该单词在其中一句话出现过,在另一句话中没出现,添加到结果数组中。
        时间复杂度: O ( n ) O(n) O(n)

class Solution {
public:
    vector<string> uncommonFromSentences(string s1, string s2) {
        unordered_map<string, int> cnt;
        string s = s1 + " " + s2;
        for (int i = 0; i < s.size(); ++ i) {
            string str = "";
            while (i < s.size() && s[i] != ' ') str += s[i ++];
            ++ cnt[str];
        }
        vector<string> ret;
        for (auto x: cnt) {
            if (x.second == 1)
                ret.emplace_back(x.first);
        }
        return ret;
    }
}; 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值