js(66)~[355] 设计推特

176 阅读2分钟

力扣本题传送门

首先搞明白这个题,核心还是求极值,最近的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