355. Design Twitter

134 阅读1分钟

image.png

方法

Tweet类实现: 每个 Tweet 实例需要记录自己的 tweetId 和发表时间 time,而且作为链表节点,要有一个指向下一个 Tweet 节点的 next 指针。

User类实现: 一个用户需要存储的信息有 userId,关注列表 (用HashSet方便快速查找),以及该用户发过的推文列表 (只存储其推文链表的头节点即可)。推文列表使用链表实现,便于进行有序合并的操作。

getNewsFeed()方法实现: 把每个用户各自的推文存储在链表里,这个链表是按 time 有序的。 如果某个用户关注了 k 个用户,可以用合并 k 个有序链表的算法合并出有序的推文列表,实现 getNewsFeed()

class Twitter {

    public class Tweet {
        Tweet next;
        int id;
        int timestamp; // sort tweet by time
        Tweet(int id, int timestamp) {
            this.id = id;
            this.timestamp = timestamp;
        }
    }

    public class User {
        public int id;
        public Set<Integer> followed;
        public Tweet head; // head of tweet linkedlist
        public User(int id) {
            this.id = id;
            followed = new HashSet<>();
            followed.add(id); // self follow, to get self tweet
        }

        public void follow(int id) {
            followed.add(id);
        }
        
        public void unfollow(int id) {
            followed.remove(id);
        }
        
        // add a tweet node to head
        public void post(int tweetId, int timestamp) {
            Tweet t = new Tweet(tweetId, timestamp);
            t.next = head;
            head = t;
        }
    }
     // global 时间戳
    int timestamp = 0;

    Map<Integer, User> userMap; // for convenience

    public Twitter() {
        userMap = new HashMap<>();
    }
    
    public void postTweet(int userId, int tweetId) {
        // new user
        if (!userMap.containsKey(userId)) {
            userMap.put(userId, new User(userId));
        }
        userMap.get(userId).post(tweetId, timestamp);
        timestamp++; // time goes
    }
    
    public List<Integer> getNewsFeed(int userId) {
        List<Integer> res = new ArrayList<>();
        if (!userMap.containsKey(userId)) {
            return res;
        }

        Set<Integer> users = userMap.get(userId).followed;

        // time大的tweet排在前面
        Queue<Tweet> pq = new PriorityQueue<>((a, b) -> (b.timestamp - a.timestamp));
        
        // 把follwee的 tweet头节点 塞到pq里
        for (int user : users) {
            Tweet t = userMap.get(user).head;
            if (t != null) {
                pq.add(t);
            }
        }

        int count = 0; // shoud be less than 10

        while (!pq.isEmpty() && count < 10) {
            Tweet t = pq.poll();
            res.add(t.id);
            count++;

            // 下一个节点也要加进pq
            if (t.next != null) {
                pq.add(t.next);
            }
        }
        return res;
    }
    
    public void follow(int followerId, int followeeId) {
        if (!userMap.containsKey(followerId)) {
            userMap.put(followerId, new User(followerId));
        }
        if (!userMap.containsKey(followeeId)) {
            userMap.put(followeeId, new User(followeeId));
        }
        userMap.get(followerId).follow(followeeId);
    }
    
    public void unfollow(int followerId, int followeeId) {
        if (!userMap.containsKey(followerId)) {
            return;
        }
        userMap.get(followerId).unfollow(followeeId);
    }
}