leecode 解题总结:355. Design Twitter

#include <iostream>
#include <stdio.h>
#include <vector>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <time.h>
#include <set>
#include <queue>
using namespace std;
/*
问题:
Design a simplified version of Twitter where users can post tweets, follow/unfollow another user and is able to see the 10 most recent tweets in the user's news feed. Your design should support the following methods:

postTweet(userId, tweetId): Compose a new tweet.
getNewsFeed(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.
follow(followerId, followeeId): Follower follows a followee.
unfollow(followerId, followeeId): Follower unfollows a followee.
Example:

Twitter twitter = new Twitter();

// User 1 posts a new tweet (id = 5).
twitter.postTweet(1, 5);

// User 1's news feed should return a list with 1 tweet id -> [5].
twitter.getNewsFeed(1);

// User 1 follows user 2.
twitter.follow(1, 2);

// User 2 posts a new tweet (id = 6).
twitter.postTweet(2, 6);

// User 1's news feed should return a list with 2 tweet ids -> [6, 5].
// Tweet id 6 should precede tweet id 5 because it is posted after tweet id 5.
twitter.getNewsFeed(1);

// User 1 unfollows user 2.
twitter.unfollow(1, 2);

// User 1's news feed should return a list with 1 tweet id -> [5],
// since user 1 is no longer following user 2.
twitter.getNewsFeed(1);

分析:此题实际上就是twiter发布微博,获取某个用户最近发布的10条微博,
设置用户关注某个用户,设置用户不关注某个用户。
1发布微博:设置一个哈希map,<用户id,set<发布的微博1,微博2...> >
考虑到后续需要取出最近10条微博,我们采用时间戳拼接tweeetId的方式组成微博标记
微博用:{时间戳,id}表示

2 获取最近10条微博,传入用户id,然后查询哈希map,返回set中前10个,注意set按时间戳从
大到小排序。
需要把其关注的用户的微博id也存入进来获取10条。
先遍历一把该用户记其所关注的所有用户的微博,然后排序输出前10个。这个太慢了。
维护一个大小为10的小顶堆,如果待插入的微博个数<10,直接插入小顶堆;
如果个数>=10,并且有当前微博的发布时间 大于 小顶堆中堆顶(发布时间最小的)微博的发布时间,
那么删除堆顶微博,插入当前微博。
这里的小顶堆实际上是优先级队列,C++优先级队列默认是大顶堆,注意greater<int> 表示 大顶堆
所以修改为小顶堆采用仿函数

3 关于用户,设定一个哈希map<用户id,<关注用户1,关注用户2,...>>
其中结构采用:unordered_map<int , unordered_set<> >
关注的时候就加入,取消关注的时候就找到该用户的关注列表,删除其不关注的用户即可

4 获取时间戳
time_t timeNow = time(NULL);

Your input

["Twitter","postTweet","getNewsFeed","follow","postTweet","getNewsFeed","unfollow","getNewsFeed"]
[      [],   [1,5],       [1],          [1,2],     [2,6],       [1],        [1,2],      [1]   ]
Your answer
[    null,    null,        [5],         null,       null,       [5],         null,       [5]  ]
Expected answer
[    null     null,        [5],         null,       null,       [6,5],       null,       [5]  ]

报错:
Input:
["Twitter","postTweet","postTweet","getNewsFeed"]
[[],[1,5],[1,3],[1]]
Output:
[null,null,null,[5]]
Expected:
[null,null,null,[3,5]]
但是发现本地和它的代码运行结果不一样,一定是优化了什么地方导致后续的没有
存入到队列,可能是

报错:
Input:
["Twitter","postTweet","follow","getNewsFeed"]
[[],[1,5],[1,1],[1]]
Output:
[null,null,null,[5,5]]
Expected:
[null,null,null,[5]]

还是报错,
Input:
["Twitter","postTweet","postTweet","postTweet","postTweet","postTweet","postTweet","postTweet","postTweet","postTweet","getNewsFeed"]
[[],[1,5],[1,3],[1,101],[1,13],[1,10],[1,2],[1,94],[1,505],[1,333],[1]]
Output:
[null,null,null,null,null,null,null,null,null,null,[13,3,10,505,2,333,94,101,5]]
Expected:
[null,null,null,null,null,null,null,null,null,null,[333,505,94,2,10,13,101,3,5]]
说明用multiset中里面比较的时候没能完全区分好,时间戳太接近了
直接用一个下标来代替时间戳,每次发一个微博,该下标累加

输入:
3(命令个数)
postTweet 1 5
postTweet 1 3
getNewsFeed 1
3
postTweet 1 5
follow 1 1
getNewsFeed 
输出:
3 5
5

关键:
1
unordered_map<int , multiset<Weibo> > _userToNews;//这里发现插入不了新的时间戳对应微博,怀疑是set去重了,用multiset
自己不能关注自己
//改为通过发微博的下标计数器来判断谁的时间在前,谁的时间在后,时间戳相同会带来问题
if(it->_index > weiboQueue.top()._index)


发布微博:设置一个哈希map,<用户id,set<发布的微博1,微博2...> >
考虑到后续需要取出最近10条微博,我们采用时间戳拼接tweeetId的方式组成微博标记
微博用:{时间戳,id}表示

2 获取最近10条微博,传入用户id,然后查询哈希map,返回set中前10个,注意set按时间戳从
大到小排序。
需要把其关注的用户的微博id也存入进来获取10条。
先遍历一把该用户记其所关注的所有用户的微博,然后排序输出前10个。这个太慢了。
维护一个大小为10的小顶堆,如果待插入的微博个数<10,直接插入小顶堆;
如果个数>=10,并且有当前微博的发布时间 大于 小顶堆中堆顶(发布时间最小的)微博的发布时间,
那么删除堆顶微博,插入当前微博。
这里的小顶堆实际上是优先级队列,C++优先级队列默认是大顶堆,注意greater<int> 表示 大顶堆
所以修改为小顶堆采用仿函数

3 关于用户,设定一个哈希map<用户id,<关注用户1,关注用户2,...>>
其中结构采用:unordered_map<int , unordered_set<> >
关注的时候就加入,取消关注的时候就找到该用户的关注列表,删除其不关注的用户即可

4 获取时间戳
time_t timeNow = time(NULL);


*/


class Weibo
{
public:
	Weibo(time_t time , int tweetId , int index):_time(time),_tweetId(tweetId),_index(index){}
	//想要按照时间越近越排在前面,时间越近,时间戳越大,已经有仿函数了
	bool operator < (const Weibo& other) const
	{
		//小顶堆用
		//return _time > other._time;
		return _index > other._index;
	}
public:
	time_t _time;//时间戳
	int _tweetId;//id
	int _index;//已经发出的微博序号
};


class Twitter {
public:
    /** Initialize your data structure here. */
    Twitter() {
        _index = 0;
    }
    
    /** Compose a new tweet. */
    void postTweet(int userId, int tweetId) {
		time_t timeNow = time(NULL);
        Weibo weibo(timeNow , tweetId , _index++);
		if(_userToNews.find(userId) != _userToNews.end())
		{
			_userToNews[userId].insert(weibo);
		}
		else
		{
			multiset<Weibo> weibos;
			weibos.insert(weibo);
			_userToNews[userId] = weibos;
		}
    }

	void storeWeibo(multiset<Weibo>& weibos , priority_queue< Weibo >& weiboQueue , int weiboSize)
	{
		for(multiset<Weibo>::iterator it = weibos.begin() ; it != weibos.end() ; it++)
		{
			if(weiboQueue.empty() || weiboQueue.size() < weiboSize)
			{
				weiboQueue.push(*it);
			}
			else
			{
				//if(it->_time > weiboQueue.top()._time)
				//改为通过发微博的下标计数器来判断谁的时间在前,谁的时间在后
				if(it->_index > weiboQueue.top()._index)
				{
					weiboQueue.pop();
					weiboQueue.push(*it);
				}
			}
		}
	}
    
    /** 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. */
    vector<int> getNewsFeed(int userId) {
		vector<int> result;
		int weiboSize = 10;
		priority_queue< Weibo > weiboQueue;
		//如果不为空
		if(_userToNews.find(userId) != _userToNews.end())
		{
			multiset<Weibo> weibos = _userToNews[userId];
			storeWeibo(weibos , weiboQueue , weiboSize);
		}
		//遍历其所有关注的用户
		if(_followerTofollowee.find(userId) != _followerTofollowee.end())
		{
			unordered_set<int> followees = _followerTofollowee[userId];
			//找到每个用户所发出的微博
			for(unordered_set<int>::iterator it = followees.begin() ; it != followees.end() ; it++)
			{
				multiset<Weibo> weibos = _userToNews[*it];
				storeWeibo(weibos , weiboQueue , weiboSize);
			}
		}
		//将队列中元素输出,堆顶是时间戳最小的,最后逆序一下即可
		while(!weiboQueue.empty())
		{
			result.push_back(weiboQueue.top()._tweetId);
			weiboQueue.pop();
		}
		reverse(result.begin() , result.end());
		return result;
    }
    
    /** Follower follows a followee. If the operation is invalid, it should be a no-op. */
    void follow(int followerId, int followeeId) {
		//自己不能关注自己
		if(followerId == followeeId)
		{
			return;
		}
		//某人去关注另一个人
		if(_followerTofollowee.find(followerId) != _followerTofollowee.end())
		{
			_followerTofollowee[followerId].insert(followeeId);
		}
		else
		{
			unordered_set<int> followees;
			followees.insert(followeeId);
			_followerTofollowee[followerId] = followees;
		}
    }
    
    /** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */
    void unfollow(int followerId, int followeeId) {
        //某人不在关注另一个人
		if(_followerTofollowee.find(followerId) != _followerTofollowee.end())
		{
			unordered_set<int> followees = _followerTofollowee[followerId];
			unordered_set<int>::iterator it = followees.find(followeeId);
			if(it != followees.end())
			{
				_followerTofollowee[followerId].erase(_followerTofollowee[followerId].find(followeeId));
				//followees.erase(it);
			}
			//如果关注的列表为空,删除映射
			if(_followerTofollowee[followerId].empty())
			{
				_followerTofollowee.erase(followerId);
			}
		}
    }

private:
	unordered_map<int , multiset<Weibo> > _userToNews;//这里发现插入不了新的时间戳对应微博,怀疑是set去重了,用multiset
	unordered_map<int , unordered_set<int> > _followerTofollowee;//某人到其关注的人的映射
	int _index;//记录已经发送的微博序号,用于后续排序使用
};

/**
 * 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);
 */

void print(vector<int>& result)
{
	if(result.empty())
	{
		cout << "no result" << endl;
		return;
	}
	int size = result.size();
	for(int i = 0 ; i < size ; i++)
	{
		cout << result.at(i) << " " ;
	}
	cout << endl;
}

void process()
{
	 int num;
	 vector<int> result;
	 string command;
	 int userId;
	 int tweetId;
	 int followerId;
	 int followeeId;
	 /*
postTweet 1 5
postTweet 1 3
getNewsFeed 1
	 */
	 while(cin >> num )
	 {
		 Twitter twitter;
		 for(int i = 0 ; i < num ; i++)
		 {
			 cin >> command;
			 if("postTweet" == command)
			 {
				 cin >> userId >> tweetId;
				 twitter.postTweet(userId , tweetId);
			 }
			 else if("getNewsFeed" == command)
			 {
				 cin >> userId;
				 result = twitter.getNewsFeed(userId);
				 print(result);
			 }
			 else if("follow" == command)
			 {
				 cin >> followerId >> followeeId;
				 twitter.follow(followerId , followeeId);
			 }
			 else if("unfollow" == command)
			 {
				 cin >> followerId >> followeeId;
				 twitter.unfollow(followerId , followeeId);
			 }
		 }
	 }
}

int main(int argc , char* argv[])
{
	process();
	getchar();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值