首先搞明白这个题,核心还是求极值,最近的10条消息,也就是维护一个大顶堆,而大顶的核心还是出堆和入堆,这个我是看着助教的讲解,撸了一遍代码,然后又加上大顶堆主要的解释,具体代码如下
/*
* @lc app=leetcode.cn id=355 lang=javascript
*
* [355] 设计推特
*/
// @lc code=start
var Twitter = function () {
this.userMap = new Map()
};
/**
* @param {number} userId
* @param {number} tweetId
* @return {void}
*/
Twitter.prototype.postTweet = function (userId, tweetId) {
if (!this.userMap.has(userId)) {
this.userMap.set(userId, new User(userId))
}
const u = this.userMap.get(userId);
u.post(tweetId);
};
/**
* @param {number} userId
* @return {number[]}
*/
Twitter.prototype.getNewsFeed = function (userId) {
let h = new MaxHeap();
let res = [];
let c = [];
// 先判断有没有用户 没有返回空数组
if (!this.userMap.has(userId)) {
return res;
}
// 获取所有关注的用户的推文
for (const ids of this.userMap.get(userId).followed) {
c = c.concat(this.userMap.get(ids).tweets)
}
// 构建最大堆
h.build(c, 'time');
// 循环拿到最近的10条信息
while (res.length < 10 && h.data.length) {
res.push(h.deleting('time').tweetId)
}
return res;
};
/**
* @param {number} followerId
* @param {number} followeeId
* @return {void}
*/
Twitter.prototype.follow = function (followerId, followeeId) {
if (!this.userMap.has(followerId)) {
this.userMap.set(followerId, new User(followerId))
}
if (!this.userMap.has(followeeId)) {
this.userMap.set(followeeId, new User(followeeId))
}
this.userMap.get(followerId).follow(followeeId);
};
/**
* @param {number} followerId
* @param {number} followeeId
* @return {void}
*/
Twitter.prototype.unfollow = function (followerId, followeeId) {
if (this.userMap.has(followerId)) {
this.userMap.get(followerId).unFollow(followeeId)
}
};
let timeStamp = 0;
let Tweet = function (tweetId, timeStamp) {
this.tweetId = tweetId;
this.time = timeStamp;
}
const User = function (userId) {
this.id = userId;
this.followed = new Set();
this.tweets = [];
this.follow(userId);
}
User.prototype.follow = function (userId) {
this.followed.add(userId);
}
User.prototype.unFollow = function (userId) {
if (userId !== this.id) {
this.followed.delete(userId);
}
}
User.prototype.post = function (tweetId) {
const tweet = new Tweet(tweetId, timeStamp);
timeStamp++;
this.tweets.unshift(tweet);
}
/**
* 最大堆 用来获取最近的10条推文
*/
function MaxHeap() {
this.data = [];
this.build = build;
// 核心 入堆 从
this.insert = insert;
this.deleting = deleting;
// 但是本题没有用
// this.heapSort = heapSort;
}
function build(arr, key) {
for (let i = 0; i < arr.length; i++) {
this.insert(arr[i], key)
}
}
/**
* 入堆 从下往上依次对比交换
* @param {*} val
* @param {*} key
*/
function insert(val, key) {
this.data.push(val);
// 1 这一步取子节点的值
let idx = this.data.length - 1;
// 2 这一步 求出父节点的下标
// 下面两行代码 计算fatherIdx是一样的
// let fatherIdx = Math.floor((idx - 1) / 2);
let fatherIdx = idx - 1 >> 1;
// 如果有父节点一次对比 往上移动
while (fatherIdx >= 0) {
// 父节点比子节点小 则交换
if (this.data[fatherIdx][key] < this.data[idx][key]) {
[this.data[fatherIdx], this.data[idx]] = [this.data[idx], this.data[fatherIdx]]
}
// 初始话idx和fatherIdx 为while循环下一步做对比
idx = fatherIdx;
fatherIdx = Math.floor((idx - 1) / 2);
}
}
/**
* 删除 就是弹出堆顶大顶堆的最大值 并且返回这个堆顶值
* @param {*} key
* @returns
*/
function deleting(key) {
// 判断如果只有一条数据直接弹出 这个还不能删除 我以为可以删除??
if (this.data.length === 1) {
return this.data.pop();
}
let idx = 0;
// 拿到老大顶堆的堆顶元素 用来返回
let val = this.data[idx];
//这一步把堆最后的一个元素赋值给堆顶 目前不知道为什么??
this.data[idx] = this.data.pop();
while (idx < this.data.length) {
let left = 2 * idx + 1;
let right = 2 * idx + 2;
let select = left;
// 判断左右子节点哪个更大 取最大值的坐标
if (right < this.data.length) {
select = this.data[left][key] < this.data[right][key] ? right : left;
}
// 判断当前新的堆顶元素(this.data[idx][key])和上一步比较出来的 左右子节点的最大值做对比 然后交换
if (select < this.data.length && this.data[idx][key] < this.data[select][key]) {
let temp = this.data[idx];
this.data[idx] = this.data[select];
this.data[select] = temp;
}
// 这一步相当于二叉堆下移 以选出来的左右子节点较大的值为跟节点 为while循环下一步做准备
idx = select;
}
return val;
}
/*
// 这一步排序 从大到小
function heapSort() {
let res = [];
while (this.data.length) {
res.unshift(this.deleting())
}
return res;
} */
/**
* Your Twitter object will be instantiated and called as such:
* var obj = new Twitter()
* obj.postTweet(userId,tweetId)
* var param_2 = obj.getNewsFeed(userId)
* obj.follow(followerId,followeeId)
* obj.unfollow(followerId,followeeId)
*/
// @lc code=end