Leetcode 355. 设计推特(中等) 多路归并&面向对象设计

355. 设计推特(中等)

题目:

Twitter 和微博功能差不多,我们主要要实现这样几个 API:

class Twitter {

    /** user 发表一条 tweet 动态 */
    public void postTweet(int userId, int tweetId) {}
    
    /** 返回该 user 关注的人(包括他自己)最近的动态 id,
    最多 10 条,而且这些动态必须按从新到旧的时间线顺序排列。*/
    public List<Integer> getNewsFeed(int userId) {}
    
    /** follower 关注 followee,如果 Id 不存在则新建 */
    public void follow(int followerId, int followeeId) {}
    
    /** follower 取关 followee,如果 Id 不存在则什么都不做 */
    public void unfollow(int followerId, int followeeId) {}

举个具体的例子,方便大家理解 API 的具体用法:

Twitter twitter = new Twitter();

twitter.postTweet(1, 5);
// 用户 1 发送了一条新推文 5

twitter.getNewsFeed(1);
// return [5],因为自己是关注自己的

twitter.follow(1, 2);
// 用户 1 关注了用户 2

twitter.postTweet(2, 6);
// 用户2发送了一个新推文 (id = 6)

twitter.getNewsFeed(1);
// return [6, 5]
// 解释:用户 1 关注了自己和用户 2,所以返回他们的最近推文
// 而且 6 必须在 5 之前,因为 6 是最近发送的

twitter.unfollow(1, 2);
// 用户 1 取消关注了用户 2

twitter.getNewsFeed(1);
// return [5]

 

思路:

labuladong

 

这几个 API 中大部分都很好实现,最核心的功能难点应该是 getNewsFeed,因为返回的结果必须在时间上有序,但问题是用户的关注是动态变化的,怎么办?

这里就涉及到算法了:如果我们把每个用户各自的推文存储在链表里,每个链表节点存储文章 id 和一个时间戳 time(记录发帖时间以便比较),而且这个链表是按 time 有序的,那么如果某个用户关注了 k 个用户,我们就可以用合并 k 个有序链表的算法合并出有序的推文列表,正确地 getNewsFeed 了

 

我们使用map<useId,User>存储用户,并且设计结构体Tweet用于保存发送推文列表,用User对象实现用户相关的功能

在User中,用unordered_set保存关注的follow,方便快速删除。用Tweet* head链表保存发送的推文。每个Tweet保存time记录发送时间,time大的在前。

 

int timestamp;
class Twitter {
public:
    // 推文
    struct Tweet{
        // 发送时间
        int time;
        int id;
        Tweet* next;
        Tweet(int i,int t){
            id=i;
            time=t;
            next=nullptr;
        }
        //用于生产大顶堆
        bool operator<(const Tweet& t) const{
            return time<t.time;
        }
    };
    // 用户
    class User{
    public:
        User(int u){
            userId=u;
            head=nullptr;
            // 首先follow一下自己,便于在归并的时候遍历
            follow(u);
        }
        // 发送推文,并将time大的放在最前边
        void postTweet(int userId, int tweetId){
            Tweet* t=new Tweet(tweetId,timestamp++);
            t->next=head;
            head=t;

        }
        void follow(int id){
            followed.emplace(id);
        }
        void unfollow(int id){
            followed.erase(id);
        }
        
        int userId;
        // 保存follow的用户id
        unordered_set<int> followed;
        // 本人发送过的推文,按time从大到小排列
        Tweet* head;
    };
public:
    Twitter() {
        timestamp=0;
    }
    
    void postTweet(int userId, int tweetId) {
        User* user;
        //如果user存在就取出,不存在就创建
        if(user_map.count(userId)>0){
            user=user_map[userId];
        }else{
            user=new User(userId);
            user_map.insert(make_pair(userId,user));
        }
        user->postTweet(userId,tweetId);
    }
    
    vector<int> getNewsFeed(int userId) {
        vector<int> ret;
        User* user;
        //用户不存在就返回空结果
        if(user_map.count(userId)>0){
            user=user_map[userId];
        }else{
            return ret;
        }
        // 大顶堆,按照time大小排列
        priority_queue<Tweet*> pq;
        //将followed列表中tweet链表放入,注意有可能有用户没有发过推文即head为NULL
        for(auto it=user->followed.begin();
                it!=user->followed.end();
                ++it){
            User* f=user_map[*it];
            if(f->head==nullptr){
                continue;
            }
            pq.push(f->head);
        }
        // 合并链表,当pq.size==0时退出
        while(!pq.empty()){
            Tweet* t=pq.top();
            pq.pop();
            ret.push_back(t->id);
            //如果tweet链表空了,pq的size就-1
            if(t->next!=nullptr){
                pq.push(t->next);
            }
            //结果满10就退出
            if(ret.size()==10){
                break;
            }
        }
        return ret;
    }
    
    void follow(int followerId, int followeeId) {
        User* follower;
        if(user_map.count(followerId)>0){
            follower=user_map[followerId];
        }else{
            follower=new User(followerId);
            user_map.insert(make_pair(followerId,follower));
        }
        User* followee;
        if(user_map.count(followeeId)>0){
            followee=user_map[followeeId];
        }else{
            followee=new User(followeeId);
            user_map.insert(make_pair(followeeId,followee));
        }
        follower->follow(followeeId);
    }
    
    void unfollow(int followerId, int followeeId) {
        User* follower;
        if(user_map.count(followerId)>0){
            follower=user_map[followerId];
        }else{
            follower=new User(followerId);
            user_map.insert(make_pair(followerId,follower));
        }
        User* followee;
        if(user_map.count(followeeId)>0){
            followee=user_map[followeeId];
        }else{
            followee=new User(followeeId);
            user_map.insert(make_pair(followeeId,followee));
        }
        follower->unfollow(followeeId);
    }
    unordered_map<int,User*> user_map;
};

 

posted @ 2022-02-24 20:59  鸭子船长  阅读(63)  评论(0编辑  收藏  举报