355:设计推特

问题描述

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

  • postTweet(userId, tweetId): 创建一条新的推文
  • getNewsFeed(userId):
    检索最近的十条推文。每个推文都必须是由此用户关注的人或者是用户自己发出的。推文必须按照时间顺序由最近的开始排序。
  • follow(followerId, followeeId): 关注一个用户
  • 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);

思路

这题坑点非常多。
你要对以下情况进行处理:

  1. 关注自己
  2. 关注不存在的人
  3. 不存在的人关注别人
  4. 不存在的人取关别人
  5. 取关不存在的人

我设计的数据结构是这样的:
一个map,对应了userId- userNode。
userNode中存储了这个user的推文,放在了一个arrayList中。
userNode还存储了关注的人,这个用hashSet存储的。

而推文则存储在了newsNode中。newsNode整个存储在了userNode中。userNode中存储了访问时间和推文ID。

在拿到最近的10个推文(很显然用堆更合适)的时候,我的做法是把该用户及该用户关注的所有用户的推文都读到一个tmp的arrayList中,重写compare方法对其进行排序。然后读前10个/前size个给结果集。 这样的时间复杂度是O(nlogn)级别的。当然啦,topK的解决方案最好是堆。在本题中,用堆的复杂度大概能降低到O(n)。
(方法一)

方法二,把方法一的结果换成了堆排序。差不多。(方法二)

后来想了想没必要把所有的元素都加到堆里来。只需要把每个人的最近10条都加进来比较就可以了。(方法三)

方法一

class newsNode{
    int twitterId;
    int time;
    newsNode(int twitterId, int time){
        this.twitterId = twitterId;
        this.time = time;
    }
}

class userNode{
    Set<Integer> follow = new HashSet<>();
    ArrayList<newsNode> news = new ArrayList<>();
    userNode(){
    }
}
class Twitter {
    Map<Integer,userNode> map;
    int time;
    /** Initialize your data structure here. */
    public Twitter() {
        map = new HashMap<>();
    }

    /** Compose a new tweet. */
    public void postTweet(int userId, int tweetId) {
        if(map.containsKey(userId)){
            // 已经有了这个用户, 插入推文
            map.get(userId).news.add(new newsNode(tweetId,time++));
        }else{
            // 没有这个用户, 创建用户,插入推文
            map.put(userId,new userNode());
            map.get(userId).news.add(new newsNode(tweetId,time++));
        }
    }

    /** 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) {
        if(!map.containsKey(userId)) return new ArrayList<>();
        ArrayList<newsNode> tmp = new ArrayList<>(map.get(userId).news);
        for(int follow: map.get(userId).follow){
            tmp.addAll(map.get(follow).news);
        }
        tmp.sort(new Comparator<newsNode>() {
            @Override
            public int compare(newsNode o1, newsNode o2) {
                if(o1 == null || o2 == null) return 0;
                return o1.time < o2.time? 1:-1;
            }
        });
        List<Integer> res = new ArrayList<>();
        for(int i = 0; i < 10 && i < tmp.size(); i++){
            res.add(tmp.get(i).twitterId);
        }
        return res;
    }

    /** Follower follows a followee. If the operation is invalid, it should be a no-op. */
    public void follow(int followerId, int followeeId) {
        if(!map.containsKey(followerId)){
            map.put(followerId,new userNode());
        }
        if(!map.containsKey(followeeId)){
            map.put(followeeId,new userNode());
        }
        if(followeeId == followerId) return;
        map.get(followerId).follow.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(!map.containsKey(followerId)) return;
        map.get(followerId).follow.remove(followeeId);
    }
}

方法二

class newsNode{
    int twitterId;
    int time;
    newsNode(int twitterId, int time){
        this.twitterId = twitterId;
        this.time = time;
    }
}

class userNode{
    Set<Integer> follow = new HashSet<>();
    ArrayList<newsNode> news = new ArrayList<>();
    userNode(){
    }
}
class Twitter {
    Map<Integer,userNode> map;
    int time;
    /** Initialize your data structure here. */
    public Twitter() {
        map = new HashMap<>();
    }

    /** Compose a new tweet. */
    public void postTweet(int userId, int tweetId) {
        if(map.containsKey(userId)){
            // 已经有了这个用户, 插入推文
            map.get(userId).news.add(new newsNode(tweetId,time++));
        }else{
            // 没有这个用户, 创建用户,插入推文
            map.put(userId,new userNode());
            map.get(userId).news.add(new newsNode(tweetId,time++));
        }
    }

    /** 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) {
        if(!map.containsKey(userId)) return new ArrayList<>();
        Comparator<newsNode> cmp = new Comparator<>() {
            public int compare(newsNode e1, newsNode e2) {
                return e1.time - e2.time;
            }
        };
        PriorityQueue<newsNode> heap = new PriorityQueue<>(cmp);
        for(newsNode n:map.get(userId).news){
            if(heap.size() < 10){
                heap.add(n);
            }else{
                heap.add(n);
                heap.poll();
            }
        }
        for(int follow: map.get(userId).follow){
            for(newsNode n:map.get(follow).news){
                if(heap.size() < 10){
                    heap.add(n);
                }else{
                    heap.add(n);
                    heap.poll();
                }
            }
        }
        List<Integer> res = new ArrayList<>();
        Stack<Integer> stack = new Stack<>();
        int max = heap.size();
        for(int i = 0; i < 10 && i < max; i++){
            stack.push(heap.poll().twitterId);
        }
        while(!stack.isEmpty()) res.add(stack.pop());
        return res;
    }

    /** Follower follows a followee. If the operation is invalid, it should be a no-op. */
    public void follow(int followerId, int followeeId) {
        if(!map.containsKey(followerId)){
            map.put(followerId,new userNode());
        }
        if(!map.containsKey(followeeId)){
            map.put(followeeId,new userNode());
        }
        if(followeeId == followerId) return;
        map.get(followerId).follow.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(!map.containsKey(followerId)) return;
        map.get(followerId).follow.remove(followeeId);
    }
}

方法三

class newsNode{
    int twitterId;
    int time;
    newsNode(int twitterId, int time){
        this.twitterId = twitterId;
        this.time = time;
    }
}

class userNode{
    Set<Integer> follow = new HashSet<>();
    ArrayList<newsNode> news = new ArrayList<>();
    userNode(){
    }
}
class Twitter {
    Map<Integer,userNode> map;
    int time;
    /** Initialize your data structure here. */
    public Twitter() {
        map = new HashMap<>();
    }

    /** Compose a new tweet. */
    public void postTweet(int userId, int tweetId) {
        if(map.containsKey(userId)){
            // 已经有了这个用户, 插入推文
            map.get(userId).news.add(new newsNode(tweetId,time++));
        }else{
            // 没有这个用户, 创建用户,插入推文
            map.put(userId,new userNode());
            map.get(userId).news.add(new newsNode(tweetId,time++));
        }
    }

    /** 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) {
        if(!map.containsKey(userId)) return new ArrayList<>();
        Comparator<newsNode> cmp = new Comparator<>() {
            public int compare(newsNode e1, newsNode e2) {
                return e1.time - e2.time;
            }
        };
        PriorityQueue<newsNode> heap = new PriorityQueue<>(cmp);
        for(int i = map.get(userId).news.size()-1; i >= 0 && heap.size() < 10; i--){
            heap.add(map.get(userId).news.get(i));
        }
        for(int follow: map.get(userId).follow){
            for(int i = map.get(follow).news.size()-1,count = 0; i >= 0 && count < 10; i--,count++){
                if(heap.size() < 10){
                    heap.add(map.get(follow).news.get(i));
                }else{
                    heap.add(map.get(follow).news.get(i));
                    heap.poll();
                }
            }
        }
        List<Integer> res = new ArrayList<>();
        Stack<Integer> stack = new Stack<>();
        int max = heap.size();
        for(int i = 0; i < 10 && i < max; i++){
            stack.push(heap.poll().twitterId);
        }
        while(!stack.isEmpty()) res.add(stack.pop());
        return res;
    }

    /** Follower follows a followee. If the operation is invalid, it should be a no-op. */
    public void follow(int followerId, int followeeId) {
        if(!map.containsKey(followerId)){
            map.put(followerId,new userNode());
        }
        if(!map.containsKey(followeeId)){
            map.put(followeeId,new userNode());
        }
        if(followeeId == followerId) return;
        map.get(followerId).follow.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(!map.containsKey(followerId)) return;
        map.get(followerId).follow.remove(followeeId);
    }
}
发布了464 篇原创文章 · 获赞 21 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_41687289/article/details/105485034
355
今日推荐