设计题:设计推特


力扣355
设计推特问题十分容易被考察到,通常都是换个皮如设计朋友圈。
我们需要设计一个推特类,并且实现以下的功能:
【1】postTweet(userId, tweetId): 创建一条新的推文
【2】getNewsFeed(userId): 检索最近的十条推文。每个推文都必须是由 此用户关注的人或者是 用户自己发出的。推文必须按照 时间顺序由最近的开始排序。
【3】follow(followerId, followeeId): 关注一个用户
【4】unfollow(followerId, followeeId): 取消关注一个用户

帖子节点

每个用户可以发出多条推特,并且这些帖子需要按照时间顺序进行排序。最直观的想法就是将推特设计成链表节点,并且保存每个帖子的tweetId,而且使用一个time成员记录帖子发出的时间。
为每个用户可以保存一个Tweet头结点,用户本身可以看作一个链表,每当用户发送一个帖子则创建一个链表节点尾插入链表,末尾的帖子节点就是最新发布的帖子。

class Tweet{
    int id;
    int time;
    Tweet next;

    public Tweet(int id, int time) {
        this.id = id;
        this.time = time;
    }
}

用户

对应用户,我们有两种处理方式:
【1】为用户设计一个User类型,每个用户有一个id,一个帖子链表的头结点和关注列表

        private int id;
        public Set<Integer> followed;
        //用户发表的推文链表头结点
        public Tweet head;

还可以在user中提供一些接口如follow和unfollow,然后提供使推特类维护一个User的集合,并且在实现上的一部分调用User提供的接口。

    private HashMap<Integer,User> userMap;

【2】另一种思路是不单独设计User类,设计类是为了更好的管理代码,而本题中我们的可以简单的使用id去代指一个user的信息。
并在推特类全局维护用户的相关信息(可以看作把User对象打散为变量来存储)

 Map<Integer,Tweet> tweetMap;//用户id-tweet
 Map<Integer,Set<Integer>> followMap;//用户id-关注列表

推特

对应推特类,我们可以使用一个全局时间作为成员,作为一个逻辑的时间,每当有一个帖子被创建则全局的逻辑时间都会递增

    int globalTime;

发帖子

(这里以第二种设计user的方案为例,即不保存User对象而保存userId Map)
发帖子是用户的行为,而且发帖子会使得全局逻辑时间自增。
这里,我们先创建一个帖子,然后put进链表,这时map.put返回值要么是null代表第一次插入,要么是一个链表节点的引用,代表就链表节点。
我们把旧链表的next指针指向新链表。使用头插法可以将插入的时间复杂度缩小到O(1),而尾插法如果不为每个user维护尾结点则必须遍历整个链表,效率不高。
因此,每个user的帖子链表,头节点代表最新的帖子

    public void postTweet(int userId, int tweetId) {
        globalTime++;
        Tweet tweet = new Tweet(tweetId, globalTime);
        Tweet res = tweetMap.put(userId, tweet);
        if(res!=null){
            //新推特在前,旧推特在后
            tweet.next=res;
        }
    }

关注和取关

    //关注别人的人 follower
    public void follow(int followerId, int followeeId) {
        if(followeeId==followerId)return; 
        if(!followMap.containsKey(followerId))
            followMap.put(followerId,new HashSet<>());
        followMap.get(followerId).add(followeeId);
    }

注意,自己不能关注和取关自己。用户可以关注多个人,因此使用一个hashSet,使用之前需要先进行初始化。

    public void unfollow(int followerId, int followeeId) {
        if(followeeId==followerId)return;
        if(!followMap.containsKey(followerId))return;
        followMap.get(followerId).remove(followeeId);

    }

关注与取关其实就是两个用户直接的hashSet做添加和删除操作。

刷新十条最新帖子

每个用户的维护一个推特头结点,且为最新节点。
一个用户有一个关注列表,那么这个关注列表可以根据tweet首节点的time进行动态排序,可以基于优先队列实现。
由于还需要显示用户自己的推特,因此将用户的tweet节点也放入优先队列。

    public List<Integer> getNewsFeed(int userId) {
    //这是一个临时创建的优先队列,用于取出最早发出的帖子
        PriorityQueue<Tweet> tweets = new PriorityQueue<>((a,b)->b.time-a.time);
        //用户自己的推特,加入优先队列
        Tweet own = tweetMap.get(userId);
        if(own!=null)
            tweets.offer(own);
        //关注者的推特
        if(!followMap.containsKey(userId))
            followMap.put(userId,new HashSet<>());
        Set<Integer> followees = followMap.get(userId);
        for(Integer id:followees){
            Tweet tweet = tweetMap.get(id);
            if(tweet!=null){
                tweets.offer(tweet);
            }
        }
        //优先队列初始化完毕...
        LinkedList<Integer> res = new LinkedList<>();
        int size=10;
        while (size>0&&!tweets.isEmpty()){
            Tweet cur = tweets.poll();
            Tweet nextTweet = cur.next;
            res.add(cur.id);
            if(nextTweet!=null)tweets.offer(nextTweet);
            size--;
        }
        return res;
    }

总结:
将用户tweet节点和关注列表成员的tweet加入优先队列,完成初始化工作。接着就是依次取出有序队列中最早发出的帖子,移除头结点,然后将处理过后的节点(node=node.next)再次放入优先队列(因为一个用户可能连续发出多条time早的帖子),依次拿出十条记录后返回结果列表。

推特项目的数据库设计需要满足以下需求: 1. 用户信息存储:需要存储用户的基本信息,如用户名、密码、邮箱、注册时间等。同时还需要存储用户的个人资料信息,如头像、个人介绍、地理位置等。 2. 推文存储:需要存储用户发布的推文,包括推文内容、发布时间、点赞数、转发数等信息。同时还需要存储推文的相关图片、视频等多媒体信息。 3. 关注与粉丝存储:需要存储用户之间的关注关系,包括用户关注的人和粉丝。同时还需要存储关注与粉丝之间的互动数据,如点赞、评论等。 4. 消息存储:需要存储用户之间的私信消息,包括消息内容、发送时间、接收者、发送者等信息。 5. 分类存储:需要存储推文的分类信息,如话、标签等,方便用户进行搜索和浏览。 6. 数据统计:需要进行数据统计和分析,如用户活跃度、推文热度、话关注度等。 为了满足以上需求,可以设计以下数据库表: 1. user表:存储用户基本信息,如用户名、密码、邮箱、注册时间等。 2. profile表:存储用户个人资料信息,如头像、个人介绍、地理位置等。 3. tweet表:存储用户发布的推文信息,如推文内容、发布时间、点赞数、转发数等。 4. media表:存储推文相关的媒体信息,如图片、视频等。 5. follow表:存储用户之间的关注关系,包括用户关注的人和粉丝。 6. interact表:存储关注与粉丝之间的互动数据,如点赞、评论等。 7. message表:存储用户之间的私信消息,包括消息内容、发送时间、接收者、发送者等信息。 8. category表:存储推文的分类信息,如话、标签等。 9. statistic表:存储数据统计和分析的结果,如用户活跃度、推文热度、话关注度等。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值