+-
PAT_甲级_1129 Recommendation System
首页 专栏 c++ 文章详情
0

PAT_甲级_1129 Recommendation System

乔梓鑫 发布于 2 月 28 日

题目大意

根据用户每次点击的东西的编号,输出他在点当前编号之前应该给这个用户推荐的商品的编号,只推荐k个,也就是输出用户曾经点击过的商品编号的最多的前k个,如果恰好两个商品有相同的点击次数,就输出编号较小的那个。

算法思路

这里根据题意很明显在每一次输入商品编号的时候需要根据排序后的结果输出推荐产品的编号,但是使用sort进行排序一定会超时,所以使用set集合的自动排序功能,排序依据的是商品的编号val和之前出现的频率,所以将这两个属性封装为一个结构体Commodity,并且重载小于号,使得在每一次添加商品后就会按照自定义的排序规则进行排序。在每一次输入的时候,只要不是第一次点击商品,那么就输出set集合中前k个商品的消息,然后再将当前商品添加到set集合中,由于该商品可能已经出现在了set集合中,所以要先查找当前商品并删除,然后再将新的商品消息添加其中。查找商品的方法就是使用num数组统计已经添加进set集合中的每一个商品编号对应的频率,然后将当前商品的编号和频率封装为Commodity,然后在set集合中查找即可。

提交结果

AC代码

#include <cstdio>
#include <set>
#include <cstring>

using namespace std;

struct Commodity{
    int val;
    int fre;
    bool operator < (Commodity node) const{
        return this->fre!=node.fre?this->fre>node.fre:this->val<node.val;
    }
    Commodity(int _val, int _fre){
        val = _val;
        fre = _fre;
    }
};

int main() {
    int n,k;
    scanf("%d %d",&n,&k);
    set<Commodity> s;
    int num[n+1];// 统计每一个数字出现的频率
    memset(num,0,sizeof(num));
    for(int i=1;i<=n;++i){
        int query;
        scanf("%d",&query);
        if(i!=1){
            printf("%d:",query);
            // 只要不是第一个数字就输出集合s中前k个数字
            int cnt = 0;
            for(auto it:s){
                if(cnt<k){
                    printf(" %d",it);
                    ++cnt;
                }else{
                    break;
                }
            }
            printf("\n");
        }
        // 添加当前数字到集合中
        Commodity toBeFound = Commodity{query, num[query]};
        auto it = s.find(toBeFound);
        if(s.find(toBeFound)!=s.end()){
            // 当前数字在s集合中出现过
            s.erase(it);
        }
        ++num[query];
        s.insert(Commodity{query, num[query]});
    }
    return 0;
}

c++ 数据结构和算法
阅读 20 发布于 2 月 28 日
收藏
分享
本作品系原创, 采用《署名-非商业性使用-禁止演绎 4.0 国际》许可协议
PAT题解
关注专栏
avatar
乔梓鑫

主要分享个人学习经验和心得

468 声望
5 粉丝
关注作者
0 条评论
得票 时间
提交评论
avatar
乔梓鑫

主要分享个人学习经验和心得

468 声望
5 粉丝
关注作者
宣传栏
目录

题目大意

根据用户每次点击的东西的编号,输出他在点当前编号之前应该给这个用户推荐的商品的编号,只推荐k个,也就是输出用户曾经点击过的商品编号的最多的前k个,如果恰好两个商品有相同的点击次数,就输出编号较小的那个。

算法思路

这里根据题意很明显在每一次输入商品编号的时候需要根据排序后的结果输出推荐产品的编号,但是使用sort进行排序一定会超时,所以使用set集合的自动排序功能,排序依据的是商品的编号val和之前出现的频率,所以将这两个属性封装为一个结构体Commodity,并且重载小于号,使得在每一次添加商品后就会按照自定义的排序规则进行排序。在每一次输入的时候,只要不是第一次点击商品,那么就输出set集合中前k个商品的消息,然后再将当前商品添加到set集合中,由于该商品可能已经出现在了set集合中,所以要先查找当前商品并删除,然后再将新的商品消息添加其中。查找商品的方法就是使用num数组统计已经添加进set集合中的每一个商品编号对应的频率,然后将当前商品的编号和频率封装为Commodity,然后在set集合中查找即可。

提交结果

AC代码

#include <cstdio>
#include <set>
#include <cstring>

using namespace std;

struct Commodity{
    int val;
    int fre;
    bool operator < (Commodity node) const{
        return this->fre!=node.fre?this->fre>node.fre:this->val<node.val;
    }
    Commodity(int _val, int _fre){
        val = _val;
        fre = _fre;
    }
};

int main() {
    int n,k;
    scanf("%d %d",&n,&k);
    set<Commodity> s;
    int num[n+1];// 统计每一个数字出现的频率
    memset(num,0,sizeof(num));
    for(int i=1;i<=n;++i){
        int query;
        scanf("%d",&query);
        if(i!=1){
            printf("%d:",query);
            // 只要不是第一个数字就输出集合s中前k个数字
            int cnt = 0;
            for(auto it:s){
                if(cnt<k){
                    printf(" %d",it);
                    ++cnt;
                }else{
                    break;
                }
            }
            printf("\n");
        }
        // 添加当前数字到集合中
        Commodity toBeFound = Commodity{query, num[query]};
        auto it = s.find(toBeFound);
        if(s.find(toBeFound)!=s.end()){
            // 当前数字在s集合中出现过
            s.erase(it);
        }
        ++num[query];
        s.insert(Commodity{query, num[query]});
    }
    return 0;
}