题解 | #小红书推荐系统#

小红书推荐系统

https://www.nowcoder.com/practice/e5b39c9034a84bf2a5e026b2b9b973d0

题目链接

小红书推荐系统

题目描述

根据小红的搜索记录(一个由空格分隔的单词组成的字符串),找出所有的“关键词”。一个单词被称为“关键词”,当且仅当它在搜索记录中出现的次数不少于3次。

请输出所有关键词,并遵循以下排序规则:

  1. 按出现频次从高到低排序。
  2. 如果频次相同,则按字典序升序排序。

解题思路

这是一个典型的词频统计和自定义排序问题。我们可以分步解决:

1. 词频统计 首先,我们需要知道每个单词在输入字符串中出现了多少次。最适合这个任务的数据结构是哈希表(在C++中是 map,Java中是 HashMap,Python中是 dict)。

  • 我们先将输入的整行字符串按空格分割成一个个独立的单词。
  • 然后,遍历这些单词。对于每个单词,我们将其作为键(key)存入哈希表,并将其出现次数作为值(value)。如果单词已存在于哈希表中,就将其计数值加1;如果不存在,就插入这个新单词,并将计数值设为1。

2. 关键词筛选 完成词频统计后,哈希表中存储了所有单词及其出现次数。根据题目定义,我们需要筛选出出现次数不少于3次的单词。我们可以遍历哈希表,将满足 count >= 3 的键值对(单词和它的频次)提取出来,存入一个新的列表或数组中,以备后续排序。

3. 自定义排序 这是本题的核心。我们需要对筛选出的关键词列表进行排序。排序规则是双重的:

  • 主排序键:单词的频次,要求降序排列。
  • 次排序键:单词本身(字符串),要求升序(字典序)排列。

在实现时,我们可以提供一个自定义的比较函数或比较器。对于任意两个关键词 A 和 B:

  • 如果 A 的频次不等于 B 的频次,那么频次高的排在前面。
  • 如果 A 的频次等于 B 的频次,那么字典序小的排在前面。

4. 输出结果 排序完成后,我们只需遍历排序好的列表,依次输出每个关键词即可。

代码

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <sstream>
#include <algorithm>

using namespace std;

// 自定义排序的比较函数
bool compare(const pair<string, int>& a, const pair<string, int>& b) {
    if (a.second != b.second) {
        return a.second > b.second; // 按频次降序
    }
    return a.first < b.first; // 频次相同,按字典序升序
}

int main() {
    string line;
    getline(cin, line);
    stringstream ss(line);
    string word;
    
    // 1. 词频统计
    map<string, int> counts;
    while (ss >> word) {
        counts[word]++;
    }
    
    // 2. 关键词筛选
    vector<pair<string, int>> keywords;
    for (auto const& [key, val] : counts) {
        if (val >= 3) {
            keywords.push_back({key, val});
        }
    }
    
    // 3. 自定义排序
    sort(keywords.begin(), keywords.end(), compare);
    
    // 4. 输出结果
    for (const auto& p : keywords) {
        cout << p.first << '\n';
    }
    
    return 0;
}
import java.util.Scanner;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String line = sc.nextLine();
        String[] words = line.split("\\s+");
        
        // 1. 词频统计
        Map<String, Integer> counts = new HashMap<>();
        for (String word : words) {
            counts.put(word, counts.getOrDefault(word, 0) + 1);
        }
        
        // 2. 关键词筛选
        List<Map.Entry<String, Integer>> keywords = new ArrayList<>();
        for (Map.Entry<String, Integer> entry : counts.entrySet()) {
            if (entry.getValue() >= 3) {
                keywords.add(entry);
            }
        }
        
        // 3. 自定义排序
        Collections.sort(keywords, (a, b) -> {
            if (!a.getValue().equals(b.getValue())) {
                return b.getValue().compareTo(a.getValue()); // 按频次降序
            }
            return a.getKey().compareTo(b.getKey()); // 频次相同,按字典序升序
        });
        
        // 4. 输出结果
        for (Map.Entry<String, Integer> entry : keywords) {
            System.out.println(entry.getKey());
        }
    }
}
import sys
from collections import Counter

def solve():
    # 读取和分割输入
    words = sys.stdin.readline().strip().split()
    
    # 1. 词频统计
    counts = Counter(words)
    
    # 2. 关键词筛选
    keywords = []
    for word, count in counts.items():
        if count >= 3:
            keywords.append((word, count))
            
    # 3. 自定义排序
    # Python的sort/sorted可以接受一个元组作为key,依次比较元组中的元素
    # 我们让频次取负数,即可实现降序排序
    keywords.sort(key=lambda x: (-x[1], x[0]))
    
    # 4. 输出结果
    for word, count in keywords:
        print(word)

solve()

算法及复杂度

  • 算法:哈希表 + 自定义排序
  • 时间复杂度:设输入字符串的总长度为 ,单词数量为 ,独立单词数量为
    • 词频统计:,因为需要遍历所有单词。
    • 筛选和排序:,这是对独立单词进行排序的开销,通常是性能瓶颈。
    • 总时间复杂度为
  • 空间复杂度:需要一个哈希表和一个列表来存储独立单词及其频次,因此空间复杂度为 ,其中 是平均单词长度。最坏情况下,空间复杂度接近
全部评论

相关推荐

08-19 17:40
Java
吴offer选手:666 打老板了吗
点赞 评论 收藏
分享
睡个觉先1555:你这个学历,这个实习,不知道你在紧张啥,包能找到好工作的
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务