设计推特--空间动态更新的Java底层实现原理

0x01.问题

设计一个简化版的推特(Twitter),可以让用户实现发送推文,关注/取消关注其他用户,能够看见关注人(包括自己)的最近十条推文。你的设计需要支持以下的几个功能:

  1. postTweet(userId, tweetId): 创建一条新的推文。
  2. getNewsFeed(userId): 检索最近的十条推文。每个推文都必须是由此用户关注的人或者是用户自己发出的。推文必须按照时间顺序由最近的开始排序。
  3. follow(followerId, followeeId): 关注一个用户。
  4. unfollow(followerId, followeeId): 取消关注一个用户

示范:
Twitter twitter = new Twitter();

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

// 用户1的获取推文应当返回一个列表,其中包含一个id为5的推文. twitter.getNewsFeed(1);

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

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

// 用户1的获取推文应当返回一个列表,其中包含两个推文,id分别为 -> [6, 5]. //
推文id6应当在推文id5之前,因为它是在5之后发送的. twitter.getNewsFeed(1);

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

// 用户1的获取推文应当返回一个列表,其中包含一个id为5的推文. // 因为用户1已经不再关注用户2.
twitter.getNewsFeed(1);

类形式:

class Twitter {

    /** Initialize your data structure here. */
    public Twitter() {

    }
    
    /** Compose a new tweet. */
    public void postTweet(int userId, int tweetId) {

    }
    
    /** Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent. */
    public List<Integer> getNewsFeed(int userId) {

    }
    
    /** Follower follows a followee. If the operation is invalid, it should be a no-op. */
    public void follow(int followerId, int followeeId) {

    }
    
    /** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */
    public void unfollow(int followerId, int followeeId) {

    }
}

/**
 * Your Twitter object will be instantiated and called as such:
 * Twitter obj = new Twitter();
 * obj.postTweet(userId,tweetId);
 * List<Integer> param_2 = obj.getNewsFeed(userId);
 * obj.follow(followerId,followeeId);
 * obj.unfollow(followerId,followeeId);
 */

0x02.底层实现原理

这其实和真实的空间动态更新,朋友圈更新的远离差不多,不用的是存放数据的位置不一样,这里就存放在内存中。

首先,我们要理清有多少种对应关系:

  • 用户与推特是一对多的关系。
  • 用户与关注列表是一对多的关系。
  • 推特应该与一个时间戳紧密关联。
  • 最终需要得到的10条最新推特也是一对多的关系。

然后,考虑这些关系的用何种数据结构存储:

  • 由于推特有自己的id,还需要时间戳来表示时间的大小,可以考虑单独封装一个类。
  • 由于用户与推特是一对多的关系,所以可以考虑将推特使用单链表存储起来,每次插入使用头插法,这样也保证了链表中推特的有序性,然后将用户id与链表的头部用哈希表对应起来。
  • 用户与关注列表是一对多,因为关注列表也只存储数字类型的用户id,所以可以将关注劣列表用set集合封装,然后用哈希表对应起来。
  • 最终需要得到的10条推特,其实就是将关注列表的链表进行排序,取前10个,这个问题就是合并k个有序链表的问题,可以使用优先队列,大顶堆来实现。
  • 另外,需要一个全局的时间戳,为推特赋予时间。

0x03.代码–哈希表+链表+优先队列

class Twitter {

    //推文类
    private class Tweet{
        private int id;//推特id
        private int timestamp;//时间戳
        private Tweet next;//指针

        //构造推文类
        public Tweet(int id, int timestamp){
            this.id = id;
            this.timestamp = timestamp;
        }
    }
    //用户与推特的对应关系哈希表
    private Map<Integer, Tweet> twitter;

    //用户与关注列表的对应关系哈希表
    private Map<Integer, Set<Integer>> followings;

    //全局时间戳
    private static int timestamp = 0;

    //合并推文的优先队列,大顶堆
    private static PriorityQueue<Tweet> maxHeap;

    /** Initialize your data structure here. */
    public Twitter() {
        followings = new HashMap<>();
        twitter = new HashMap<>();
        //根据时间戳来确定的大顶堆
        maxHeap = new PriorityQueue<>((o1, o2) -> -o1.timestamp + o2.timestamp);
    }
    
    /** Compose a new tweet. */
    public void postTweet(int userId, int tweetId) {
        timestamp++;
        //id已经存在
        if (twitter.containsKey(userId)) {
            Tweet pre=twitter.get(userId);
            Tweet curr=new Tweet(tweetId,timestamp);
            curr.next=pre;//链表的头插法
            twitter.put(userId,curr);
        }else{//新建一个用户
            twitter.put(userId, new Tweet(tweetId, timestamp));
        }
    }
    
    /** Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent. */
    public List<Integer> getNewsFeed(int userId) {
        //重置大顶堆
        maxHeap.clear();
        //获取关注列表
        Set<Integer> followingList = followings.get(userId);
        //加上自己发的推文
        if (twitter.containsKey(userId)) {
            maxHeap.offer(twitter.get(userId));
        }
        //遍历关注者的推文,加入大顶堆
        if (followingList != null && followingList.size() > 0) {
            for (Integer followingId : followingList) {
                Tweet tweet = twitter.get(followingId);
                if (tweet != null) {
                    maxHeap.offer(tweet);
                }
            }
        }
        //准备返回的推文集合
        List<Integer> result = new ArrayList<Integer>(10);
        int cou=0;//计数
        while (!maxHeap.isEmpty() && cou < 10) {
            Tweet head = maxHeap.poll();//获取堆顶元素
            result.add(head.id);
            //将头的下一个重新加入大顶堆
            if(head.next!=null){
                maxHeap.offer(head.next);
            }
            cou++;
        }
        return result;
    }
    
    /** Follower follows a followee. If the operation is invalid, it should be a no-op. */
    public void follow(int followerId, int followeeId) {
        //不能关注自己
        if (followeeId == followerId) {
            return;
        }
        //获取关注集合
        Set<Integer> followingList = followings.get(followerId);
        //还未关注任何人,则新建一个哈希表
        if (followingList == null) {
             Set<Integer> init = new HashSet<Integer>();
             init.add(followeeId);
             followings.put(followerId, init);
        }else{
            //已经关注过此人了
            if (followingList.contains(followeeId)) {
                return;
            }
            //加入关注集合
            followingList.add(followeeId);
        }
    }
    
    /** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */
    //和关注差不多
    public void unfollow(int followerId, int followeeId) {
        if (followeeId == followerId) {
             return;
        }
        Set<Integer> followingList = followings.get(followerId);
        if (followingList == null) {
            return;
        }
        followingList.remove(followeeId);
    }
}

你知道为什么车到山前必有路吗?
因为有人已经帮你准备好了路。

ATFWUS --Writing By 2020–04-13

基于Transformer的疫情期间推特情感分析是一种利用Transformer模型进行情感分析的方法,该方法可以帮助我们了解人们在疫情期间对于相关话题的情感倾向。 Transformer是一种基于自注意力机制的神经网络模型,它在自然语言处理任务中取得了很好的效果。在情感分析任务中,我们可以使用Transformer模型来学习推特文本中的情感信息。 GPU(图形处理器)是一种用于加速计算的硬件设备,它可以并行处理大规模数据,提高模型训练和推理的速度。在进行基于Transformer的情感分析时,使用GPU可以显著提高模型的训练和推理效率。 为了进行基于Transformer的疫情期间推特情感分析,我们可以按照以下步骤进行: 1. 数据收集:收集与疫情相关的推特数据集,包括推特文本和对应的情感标签。 2. 数据预处理:对推特文本进行清洗、分词等预处理操作,将其转化为模型可接受的输入格式。 3. 模型构建:构建基于Transformer的情感分析模型,包括编码器和解码器部分。 4. 模型训练:使用收集到的推特数据集对模型进行训练,通过最小化损失函数来优化模型参数。 5. 模型评估:使用评估数据集对训练好的模型进行评估,计算模型在情感分析任务上的性能指标,如准确率、精确率、召回率等。 6. 模型应用:使用训练好的模型对新的推特文本进行情感分析预测,得到文本的情感倾向。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ATFWUS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值