819.最常见的单词——Leetcode每日一题(2022.4.17)

819.最常见的单词——Leetcode每日一题(2022.4.17)

前言

今天早起A了这道题,昨天先是高铁上打力扣杯,晚上打双周赛,今天早上A完这题有去打周赛,强度拉满了属于是。

不过,yysy,一开始看到题目的时候,嗯,绿色题,看我不秒了它,欸,错了!一定是那里不对,改一下,挖草,又错了!就这样反复几次,终于对了。只能说这道题目看似很简单的题目,但是暗藏的细节还是很多的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WvTa92da-1650204164395)(C:\Users\86152\AppData\Roaming\Typora\typora-user-images\image-20220417194408970.png)]

该题链接819. 最常见的单词 - 力扣(LeetCode) (leetcode-cn.com)

以下关于题目的来源都来自leetcode官方。

题目描述

给定一个段落 (paragraph) 和一个禁用单词列表 (banned)。返回出现次数最多,同时不在禁用列表中的单词。

题目保证至少有一个词不在禁用列表中,而且答案唯一。

禁用列表中的单词用小写字母表示,不含标点符号。段落中的单词不区分大小写。答案都是小写字母。

示例

输入: 
paragraph = "Bob hit a ball, the hit BALL flew far after it was hit."
banned = ["hit"]
输出: "ball"
解释: 
"hit" 出现了3次,但它是一个禁用的单词。
"ball" 出现了2次 (同时没有其他单词出现2次),所以它是段落里出现次数最多的,且不在禁用列表中的单词。 
注意,所有这些单词在段落里不区分大小写,标点符号需要忽略(即使是紧挨着单词也忽略, 比如 "ball,"), 
"hit"不是最终的答案,虽然它出现次数更多,但它在禁用单词列表中。

提示

1 <= 段落长度 <= 1000
0 <= 禁用单词个数 <= 100
1 <= 禁用单词长度 <= 10
答案是唯一的, 且都是小写字母 (即使在 paragraph 里是大写的,即使是一些特定的名词,答案都是小写的。)
paragraph 只包含字母、空格和下列标点符号!?’,;.
不存在没有连字符或者带有连字符的单词。
单词里只包含字母,不会出现省略号或者其他标点符号。

解题思路——哈希表

我觉得看到这种题目,有一定经验都没啥好说的吧,直接哈希表就完事了。

我们可以使用一个哈希表去存储ban的单词,这样我们可以只用o(n)的空间来换取,暴力的查找带来O(m*n)的时间,置需要O(1)的时间复杂即可,显然是很划算的。

:n为ban数组的长度,而m是段落的长度。、

当然我们在遍历字符串的时候,其实也需要使用一个哈希表来完成单词的计数,我们可以ban的哈希表跳过一些被ban的单词的计数。

最后是一些细节问题,由于规定是小写,所以我们需要把大写转换成小写,然后遍历的时候记录字母,拼成单词,当遇到非字母时则需要进行中断的单词判断。

code(C++)

#include<iostream>
#include<string>
#include<vector>
#include<unordered_map>
using namespace std;

class Solution 
{
public:
    /// <summary>
    /// 哈希表
    /// </summary>
    /// <param name="paragraph"></param>
    /// <param name="banned"></param>
    /// <returns></returns>
    string mostCommonWord(string paragraph, vector<string>& banned) 
    {
        // 先用哈希表存储列表中的字符串
        unordered_map<string, int> ban;
        for (string b : banned)
        {
            transLower(b);
            ban[b]++;
        }
        // 然后再用另外一个哈希表存储段落中的非ban单词出现的次数
        unordered_map<string, int> time;
        int len = paragraph.length();
        string ans = "";
        string word = "";
        // 重新写了循环判断,原来的靠标点符号,有点过于麻烦
        // 只需判断是否是字母
        for (int i = 0; i < len; ++i)
        {
            char ch = paragraph[i];
            if (ch >= 65 && ch <= 90 || ch >= 97 && ch <= 122)
            {
                // 大写转小写
                if (ch >= 65 && ch <= 90)
                {
                    ch += 32;
                }
                word += ch;
            }
            // 去除空字符串的情况带来的影响,保证一定有单词
            else if(word != "")
            {
                // 哈希表判断是否被ban
                if (ban[word] != 1)
                {
                    // 该单词的次数+1
                    time[word]++;
                    // 动态更新结果答案
                    if (word != "" && (ans == "" || time[word] > time[ans]))
                    {
                        ans = word;
                    }
                }
                // 将单词字符串清空
                word = "";
            }
        }
        // 最后一个单词的情况
        if (ban[word] != 1)
        {
            time[word]++;
        }
        if (ans == "" || time[word] > time[ans])
        {
            ans = word;
        }
        return ans;
    }
private:
    // 写一个单词转小写的函数
    void transLower(string& word)
    {
        for (char& ch : word)
        {
            if (ch >= 65 && ch <= 90)
            {
                ch += 32;
            }
        }
    }
};

int main(int argc, char** argv)
{
    int n;
    string par;
    while (getline(cin, par))
    {
        cin >> n;
        vector<string> ban(n);
        for (string& b : ban)
        {
            cin >> b;
        }
        Solution sol;
        cout << sol.mostCommonWord(par, ban) << endl;
    }

	return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值