边工作边刷题:70天一遍leetcode: day 44

Design Twitter

要点:这实际是一道设计题,这类题通常就是选择data structure来实现get和put逻辑。

  • twitter主要操作是getNewsFeed,这题的要求是某user和其followee的最近10个tweets。类似n-way merge,用PriorityQueue来实现。因为java的PriorityQueue只接受一个generic type,所以用uid的Integer,同时有效利用anonymous class和enclosing class相同scope的特性来得到其他信息。
  • 显然这是pull-based的model
  • put tweets就是对每个user一个list:tweetsMap。这样merge的时候,就只需遍历当前user及其followee即可:用followeeMap存这个关系。核心的成员变量就是这两个。
  • 因为下一次call getNewsFeed的时候以前显示过的tweets还要显示,所以不能从user tweetsList中删除,只能用idxMap记录当前位置。这个是local的变量。
  • 题中tweetId并不一定是按时间递增的,所以要用tweetCountMap记录tweet的时间顺序

错误点:

  • java.lang.NullPointerException:user可能没有followee,所以要先检查null
  • tweetsList也可能为空,同样在initial put PriorityQueue时要check
  • follow/unfollow中不能follow自己,否则同一个user入queue两次,tweet idx会过界

Python

  • 只需要tweetsMap和followeeMap,利用了python容易存tuple的特点,把time和每个post存一起,简化了不少
  • 类似,PriorityQueue中存tuple,来保存time,tweetID,userId,idx(remember,Java利用的是Comparator function直接访问enclosing data structure,而python的heapq是不能指定cmp的,所以存下所有信息)
  • getNewsFeed: java中user和其followee要分别加入pq,而python可以用’|’来combine两个set
  • 注意dict的default ops get(), 需要有括号:set()。否则syntax error: TypeError: unsupported operand type(s) for |: 'type' and ‘set’。而defaultdict不需要
from heapq import *
class Twitter(object):

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.tweetsMap = {}
        self.followeeMap = {}
        self.time = 0

    def postTweet(self, userId, tweetId):
        """
        Compose a new tweet.
        :type userId: int
        :type tweetId: int
        :rtype: void
        """
        self.tweetsMap.setdefault(userId, list())
        self.tweetsMap[userId].append((self.time, tweetId))
        self.time+=1

    def getNewsFeed(self, userId):
        """
        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.
        :type userId: int
        :rtype: List[int]
        """
        pq = []
        people = self.followeeMap.get(userId, set()) | set([userId]) # error 1: set has no () =>  TypeError: unsupported operand type(s) for |: 'type' and 'set'
        for person in people:
            if person in self.tweetsMap and self.tweetsMap:
                time, tweetId = self.tweetsMap[person][-1]
                heappush(pq, (-time, tweetId, person, len(self.tweetsMap[person])-1))
        news = []
        while len(news)<10 and pq:
            time, tweetId, person, idx = heappop(pq)
            news.append(tweetId)
            if idx>0:
                time, tweetId = self.tweetsMap[person][idx-1]
                heappush(pq, (-time, tweetId, person, idx-1))
        
        return news

    def follow(self, followerId, followeeId):
        """
        Follower follows a followee. If the operation is invalid, it should be a no-op.
        :type followerId: int
        :type followeeId: int
        :rtype: void
        """
        if followerId==followeeId:
            return
        
        self.followeeMap[followerId]=self.followeeMap.get(followerId, set()) | {followeeId}
        

    def unfollow(self, followerId, followeeId):
        """
        Follower unfollows a followee. If the operation is invalid, it should be a no-op.
        :type followerId: int
        :type followeeId: int
        :rtype: void
        """
        if followerId==followeeId:
            return
        if followerId in self.followeeMap:
            self.followeeMap[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)

原文地址:https://www.cnblogs.com/absolute/p/5690303.html