列表

详情


355. 设计推特

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

实现 Twitter 类:

 

示例:

输入
["Twitter", "postTweet", "getNewsFeed", "follow", "postTweet", "getNewsFeed", "unfollow", "getNewsFeed"]
[[], [1, 5], [1], [1, 2], [2, 6], [1], [1, 2], [1]]
输出
[null, null, [5], null, null, [6, 5], null, [5]]

解释
Twitter twitter = new Twitter();
twitter.postTweet(1, 5); // 用户 1 发送了一条新推文 (用户 id = 1, 推文 id = 5)
twitter.getNewsFeed(1);  // 用户 1 的获取推文应当返回一个列表,其中包含一个 id 为 5 的推文
twitter.follow(1, 2);    // 用户 1 关注了用户 2
twitter.postTweet(2, 6); // 用户 2 发送了一个新推文 (推文 id = 6)
twitter.getNewsFeed(1);  // 用户 1 的获取推文应当返回一个列表,其中包含两个推文,id 分别为 -> [6, 5] 。推文 id 6 应当在推文 id 5 之前,因为它是在 5 之后发送的
twitter.unfollow(1, 2);  // 用户 1 取消关注了用户 2
twitter.getNewsFeed(1);  // 用户 1 获取推文应当返回一个列表,其中包含一个 id 为 5 的推文。因为用户 1 已经不再关注用户 2

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Twitter { public: Twitter() { } void postTweet(int userId, int tweetId) { } vector<int> getNewsFeed(int userId) { } void follow(int followerId, int followeeId) { } void unfollow(int followerId, int followeeId) { } }; /** * Your Twitter object will be instantiated and called as such: * Twitter* obj = new Twitter(); * obj->postTweet(userId,tweetId); * vector<int> param_2 = obj->getNewsFeed(userId); * obj->follow(followerId,followeeId); * obj->unfollow(followerId,followeeId); */

golang 解法, 执行用时: 0 ms, 内存消耗: 2 MB, 提交时间: 2023-09-11 10:57:12

type Twitter struct {
	Tweets []int
	UserTweets map[int][]int
	Follows map[int][]int
	IsFollowMy map[int]bool
}

/** Initialize your data structure here. */
func Constructor() Twitter {
	// 每一次实例化的时候,都重新分配一次,这样不会造成示例重复
	var Tweets  []int
	// 某用户发的某条推特
	var UserTweets = make(map[int][]int)
	// 某用户关注了哪些用户
	var Follows = make(map[int][]int)
	var IsFollowMy = make(map[int]bool)

	t := Twitter{
		Tweets: Tweets,
		UserTweets: UserTweets,
		Follows: Follows,
		IsFollowMy: IsFollowMy,
	}
	return t
}


/** Compose a new tweet. */
func (this *Twitter) PostTweet(userId int, tweetId int)  {
	// 每个人每次发推特,都记录到一个地方
	this.Tweets = append(this.Tweets, tweetId)
	// 某个用户发了推特,存到自己推特列表里
	this.UserTweets[userId] = append(this.UserTweets[userId], 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. */
func (this *Twitter) GetNewsFeed(userId int) []int {
	fs := this.Follows[userId] // 先获取该用户的关注列表
	var allTweets []int
	for _,v := range fs {
		// 把关注列表的人的所有推特都集中起来
		allTweets = append(allTweets, this.UserTweets[v]...)
	}
	if !this.IsFollowMy[userId] {
		// 如果自己没有关注自己,那么也需要把自己发的推特加到一起
		allTweets = append(allTweets, this.UserTweets[userId]...)
	}
	var sortTweets []int
	aTLen := len(this.Tweets)
	s := 0
	// 按照发的推特顺序进行倒序排序
	for i:=aTLen-1;i>=0;i-- {
		if s >= 10 {
			break
		}
		for _,n := range allTweets {
			
			// 只取 10条数据
			if this.Tweets[i] == n && s < 10{
				s++
				sortTweets = append(sortTweets,n)
			}
		}
	}

	return sortTweets
}


/** Follower follows a followee. If the operation is invalid, it should be a no-op. */
func (this *Twitter) Follow(followerId int, followeeId int)  {
	// 如果自己关注了自己,标记一下
	if followerId == followeeId {
		this.IsFollowMy[followerId] = true
	}
	
	// 下面是判断这人是否关注了,如果已经关注了,那么就不再关注了
	var isFed bool
	for _,v := range this.Follows[followerId] {
		if v == followeeId {
			isFed = true
		}
	}
	if !isFed {
		this.Follows[followerId] = append(this.Follows[followerId], followeeId)
	}
}


/** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */
func (this *Twitter) Unfollow(followerId int, followeeId int)  {
	// 如果自己取关了自己,标记一下
	if followeeId == followerId {
		this.IsFollowMy[followerId] = false
	}
	
	// 去掉自己关注列表里那个被关注的人
	var temp []int
	for _,v := range this.Follows[followerId] {
		if v != followeeId {
			temp = append(temp, v)
		}
	}
	this.Follows[followerId] = temp
}
/**
 * Your Twitter object will be instantiated and called as such:
 * obj := Constructor();
 * obj.PostTweet(userId,tweetId);
 * param_2 := obj.GetNewsFeed(userId);
 * obj.Follow(followerId,followeeId);
 * obj.Unfollow(followerId,followeeId);
 */

php 解法, 执行用时: 8 ms, 内存消耗: 18.9 MB, 提交时间: 2023-09-11 10:54:41

class Twitter {
    /**
     * Initialize your data structure here.
     */
    function __construct() {
        $this->timestamp = 0;
        $this->tweets = [];
        $this->followers = [];
    }
  
    /**
     * Compose a new tweet.
     * @param Integer $userId
     * @param Integer $tweetId
     * @return NULL
     */
    function postTweet($userId, $tweetId) {
        $this->tweets[$userId][] = [$tweetId,$this->timestamp];
        $this->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.
     * @param Integer $userId
     * @return Integer[]
     */
    function getNewsFeed($userId) {
        $tweets = [];
        if(!empty($this->tweets[$userId])) $tweets = $this->tweets[$userId];
        if(!empty($this->followers[$userId])){
            foreach($this->followers[$userId] as $followeeId=>$v){
                if($followeeId == $userId) continue;
                $tweets = array_merge($tweets, $this->tweets[$followeeId] ?? []);
            }
        }
        $sq = new SplPriorityQueue();
        foreach($tweets as $t){
            $tweetId = $t[0];
            $timestamp = $t[1];
            $sq->insert($tweetId, $timestamp);
        }
        $i=0;
        $ans = [];
        while($i<10 && !$sq->isEmpty()){
            $ans[] = $sq->extract();
            $i++;
        }
        return $ans;
    }
  
    /**
     * Follower follows a followee. If the operation is invalid, it should be a no-op.
     * @param Integer $followerId
     * @param Integer $followeeId
     * @return NULL
     */
    function follow($followerId, $followeeId) {
        $this->followers[$followerId][$followeeId] = 1;
    }
  
    /**
     * Follower unfollows a followee. If the operation is invalid, it should be a no-op.
     * @param Integer $followerId
     * @param Integer $followeeId
     * @return NULL
     */
    function unfollow($followerId, $followeeId) {
        unset($this->followers[$followerId][$followeeId]);
    }
}

/**
 * Your Twitter object will be instantiated and called as such:
 * $obj = Twitter();
 * $obj->postTweet($userId, $tweetId);
 * $ret_2 = $obj->getNewsFeed($userId);
 * $obj->follow($followerId, $followeeId);
 * $obj->unfollow($followerId, $followeeId);
 */

java 解法, 执行用时: 11 ms, 内存消耗: 39.8 MB, 提交时间: 2023-09-11 10:52:14

class Twitter {
    private class Node {
        // 哈希表存储关注人的 Id
        Set<Integer> followee;
        // 用链表存储 tweetId
        LinkedList<Integer> tweet;

        Node() {
            followee = new HashSet<Integer>();
            tweet = new LinkedList<Integer>();
        }
    }

    // getNewsFeed 检索的推文的上限以及 tweetId 的时间戳
    private int recentMax, time;
    // tweetId 对应发送的时间
    private Map<Integer, Integer> tweetTime;
    // 每个用户存储的信息
    private Map<Integer, Node> user;

    public Twitter() {
        time = 0;
        recentMax = 10;
        tweetTime = new HashMap<Integer, Integer>();
        user = new HashMap<Integer, Node>();
    }

    // 初始化
    public void init(int userId) {
        user.put(userId, new Node());
    }

    public void postTweet(int userId, int tweetId) {
        if (!user.containsKey(userId)) {
            init(userId);
        }
        // 达到限制,剔除链表末尾元素
        if (user.get(userId).tweet.size() == recentMax) {
            user.get(userId).tweet.remove(recentMax - 1);
        }
        user.get(userId).tweet.addFirst(tweetId);
        tweetTime.put(tweetId, ++time);
    }
    
    public List<Integer> getNewsFeed(int userId) {
        LinkedList<Integer> ans = new LinkedList<Integer>();
        for (int it : user.getOrDefault(userId, new Node()).tweet) {
            ans.addLast(it);
        }
        for (int followeeId : user.getOrDefault(userId, new Node()).followee) {
            if (followeeId == userId) { // 可能出现自己关注自己的情况
                continue;
            }
            LinkedList<Integer> res = new LinkedList<Integer>();
            int tweetSize = user.get(followeeId).tweet.size();
            Iterator<Integer> it = user.get(followeeId).tweet.iterator();
            int i = 0;
            int j = 0;
            int curr = -1;
            // 线性归并
            if (j < tweetSize) {
                curr = it.next();
                while (i < ans.size() && j < tweetSize) {
                    if (tweetTime.get(curr) > tweetTime.get(ans.get(i))) {
                        res.addLast(curr);
                        ++j;
                        if (it.hasNext()) {
                            curr = it.next();
                        }
                    } else {
                        res.addLast(ans.get(i));
                        ++i;
                    }
                    // 已经找到这两个链表合起来后最近的 recentMax 条推文
                    if (res.size() == recentMax) {
                        break;
                    }
                }
            }
            for (; i < ans.size() && res.size() < recentMax; ++i) {
                res.addLast(ans.get(i));
            }
            if (j < tweetSize && res.size() < recentMax) {
                res.addLast(curr);
                for (; it.hasNext() && res.size() < recentMax;) {
                    res.addLast(it.next());
                }
            }
            ans = new LinkedList<Integer>(res);
        }
        return ans;
    }
    
    public void follow(int followerId, int followeeId) {
        if (!user.containsKey(followerId)) {
            init(followerId);
        }
        if (!user.containsKey(followeeId)) {
            init(followeeId);
        }
        user.get(followerId).followee.add(followeeId);
    }
    
    public void unfollow(int followerId, int followeeId) {
        user.getOrDefault(followerId, new Node()).followee.remove(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);
 */

python3 解法, 执行用时: 40 ms, 内存消耗: 16.1 MB, 提交时间: 2023-09-11 10:51:54

class Twitter:

    class Node:
        def __init__(self):
            self.followee = set()
            self.tweet = list()

    def __init__(self):
        self.time = 0
        self.recentMax = 10
        self.tweetTime = dict()
        self.user = dict()

    def postTweet(self, userId: int, tweetId: int) -> None:
        if userId not in self.user:
            self.user[userId] = Twitter.Node()
        self.user[userId].tweet.append(tweetId)
        self.time += 1
        self.tweetTime[tweetId] = self.time

    def getNewsFeed(self, userId: int) -> List[int]:
        if userId not in self.user:
            return list()
        ans = self.user[userId].tweet[-10:][::-1]
        for followeeId in self.user[userId].followee:
            if followeeId in self.user:
                opt = self.user[followeeId].tweet[-10:][::-1]
                i, j, combined = 0, 0, list()
                while i < len(ans) and j < len(opt):
                    if self.tweetTime[ans[i]] > self.tweetTime[opt[j]]:
                        combined.append(ans[i])
                        i += 1
                    else:
                        combined.append(opt[j])
                        j += 1
                combined.extend(ans[i:])
                combined.extend(opt[j:])
                ans = combined[:10]
        return ans

    def follow(self, followerId: int, followeeId: int) -> None:
        if followerId != followeeId:
            if followerId not in self.user:
                self.user[followerId] = Twitter.Node()
            self.user[followerId].followee.add(followeeId)
            
    def unfollow(self, followerId: int, followeeId: int) -> None:
        if followerId != followeeId:
            if followerId in self.user:
                self.user[followerId].followee.discard(followeeId)


# Your Twitter object will be instantiated and called as such:
# obj = Twitter()
# obj.postTweet(userId,tweetId)
# param_2 = obj.getNewsFeed(userId)
# obj.follow(followerId,followeeId)
# obj.unfollow(followerId,followeeId)

python3 解法, 执行用时: 36 ms, 内存消耗: 15.9 MB, 提交时间: 2023-09-11 10:49:57

import collections
import heapq
import itertools

class Twitter(object):
    def __init__(self):
        self.timer = itertools.count(step=-1)
        self.tweets = collections.defaultdict(collections.deque)
        self.followees = collections.defaultdict(set)

    def postTweet(self, userId, tweetId):
        self.tweets[userId].appendleft((next(self.timer), tweetId))

    def getNewsFeed(self, userId):
        # 注意| {userId} 需要并上自己的推文
        tweets = heapq.merge(*(self.tweets[u] for u in self.followees[userId] | {userId}))
        # 至多取前10项
        return [t for _, t in itertools.islice(tweets, 10)]

    def follow(self, followerId, followeeId):
        self.followees[followerId].add(followeeId)

    def unfollow(self, followerId, followeeId):
        self.followees[followerId].discard(followeeId)


# Your Twitter object will be instantiated and called as such:
# obj = Twitter()
# obj.postTweet(userId,tweetId)
# param_2 = obj.getNewsFeed(userId)
# obj.follow(followerId,followeeId)
# obj.unfollow(followerId,followeeId)

上一题