【映射 堆 】1912. 设计电影租借系统

本文涉及知识点

映射

LeetCode1912. 设计电影租借系统

你有一个电影租借公司和 n 个电影商店。你想要实现一个电影租借系统,它支持查询、预订和返还电影的操作。同时系统还能生成一份当前被借出电影的报告。
所有电影用二维整数数组 entries 表示,其中 entries[i] = [shopi, moviei, pricei] 表示商店 shopi 有一份电影 moviei 的拷贝,租借价格为 pricei 。每个商店有 至多一份 编号为 moviei 的电影拷贝。
系统需要支持以下操作:
Search:找到拥有指定电影且 未借出 的商店中 最便宜的 5 个 。商店需要按照 价格 升序排序,如果价格相同,则 shopi 较小 的商店排在前面。如果查询结果少于 5 个商店,则将它们全部返回。如果查询结果没有任何商店,则返回空列表。
Rent:从指定商店借出指定电影,题目保证指定电影在指定商店 未借出 。
Drop:在指定商店返还 之前已借出 的指定电影。
Report:返回 最便宜的 5 部已借出电影 (可能有重复的电影 ID),将结果用二维列表 res 返回,其中 res[j] = [shopj, moviej] 表示第 j 便宜的已借出电影是从商店 shopj 借出的电影 moviej 。res 中的电影需要按 价格 升序排序;如果价格相同,则 shopj 较小 的排在前面;如果仍然相同,则 moviej 较小 的排在前面。如果当前借出的电影小于 5 部,则将它们全部返回。如果当前没有借出电影,则返回一个空的列表。
请你实现 MovieRentingSystem 类:

MovieRentingSystem(int n, int[][] entries) 将 MovieRentingSystem 对象用 n 个商店和 entries 表示的电影列表初始化。
List search(int movie) 如上所述,返回 未借出 指定 movie 的商店列表。
void rent(int shop, int movie) 从指定商店 shop 借出指定电影 movie 。
void drop(int shop, int movie) 在指定商店 shop 返还之前借出的电影 movie 。
List<List> report() 如上所述,返回最便宜的 已借出 电影列表。
注意:测试数据保证 rent 操作中指定商店拥有 未借出 的指定电影,且 drop 操作指定的商店 之前已借出 指定电影。

示例 1:
输入:
[“MovieRentingSystem”, “search”, “rent”, “rent”, “report”, “drop”, “search”]
[[3, [[0, 1, 5], [0, 2, 6], [0, 3, 7], [1, 1, 4], [1, 2, 7], [2, 1, 5]]], [1], [0, 1], [1, 2], [], [1, 2], [2]]
输出:
[null, [1, 0, 2], null, null, [[0, 1], [1, 2]], null, [0, 1]]
解释:
MovieRentingSystem movieRentingSystem = new MovieRentingSystem(3, [[0, 1, 5], [0, 2, 6], [0, 3, 7], [1, 1, 4], [1, 2, 7], [2, 1, 5]]);
movieRentingSystem.search(1); // 返回 [1, 0, 2] ,商店 1,0 和 2 有未借出的 ID 为 1 的电影。商店 1 最便宜,商店 0 和 2 价格相同,所以按商店编号排序。
movieRentingSystem.rent(0, 1); // 从商店 0 借出电影 1 。现在商店 0 未借出电影编号为 [2,3] 。
movieRentingSystem.rent(1, 2); // 从商店 1 借出电影 2 。现在商店 1 未借出的电影编号为 [1] 。
movieRentingSystem.report(); // 返回 [[0, 1], [1, 2]] 。商店 0 借出的电影 1 最便宜,然后是商店 1 借出的电影 2 。
movieRentingSystem.drop(1, 2); // 在商店 1 返还电影 2 。现在商店 1 未借出的电影编号为 [1,2] 。
movieRentingSystem.search(2); // 返回 [0, 1] 。商店 0 和 1 有未借出的 ID 为 2 的电影。商店 0 最便宜,然后是商店 1 。

提示:
1 <= n <= 3 * 105
1 <= entries.length <= 105
0 <= shopi < n
1 <= moviei, pricei <= 104
每个商店 至多 有一份电影 moviei 的拷贝。
search,rent,drop 和 report 的调用 总共 不超过 105 次。

懒惰堆

m_mPriece[商店][电影id] = 价格
二维映射换成一维映射效率更高,需要自写哈希函数。
m_search[move]有序集合记录所有未借出的电影的价格、shop。
有序集合m_setReport记录所有出借的电影,价格 、商店、电影id。
用懒惰堆 也可以,只是麻烦些。

代码

class MovieRentingSystem {
public:
	MovieRentingSystem(int n, vector<vector<int>>& entries) {
		for (const auto& v : entries) {
			m_mPrice[make_pair(v[0], v[1])] = v[2];
			mMove[v[1]].emplace(make_pair(v[2],v[0]));
		}
	}

	vector<int> search(int movie) {
		const auto& s = mMove[movie];
		vector<int> ret;
		for (auto tmp : s) {
			ret.emplace_back(tmp.second);
			if (ret.size() >= 5) { break; }
		}
		return ret;
	}

	void rent(int shop, int movie) {
		const int price = m_mPrice[make_pair(shop, movie)];
		mMove[movie].erase(make_pair(price,shop));
		m_rent.emplace(make_tuple(price, shop, movie));
	}

	void drop(int shop, int movie) {
		const int price = m_mPrice[make_pair(shop, movie)];
		m_rent.erase(make_tuple(price, shop, movie));
		mMove[movie].emplace(make_pair(price, shop));
	}

	vector<vector<int>> report() {
		vector<vector<int>> ret;
		for (auto& [price, shop, move]: m_rent) {
			ret.emplace_back(vector<int>{shop,move});
			if (ret.size() >= 5) { break; }
		}
		return ret;
	}
	struct SPosHash {
		// 哈希函数的操作符重载,接受一个指针作为参数
		size_t operator()(const std::pair<int, int>& pos) const {
			// 简单的哈希函数示例,将指针地址转换为哈希值
			return pos.first*100'000L+pos.second;;
		}
	};
	unordered_map<int, set<pair<int, int>>> mMove;
	set<tuple<int, int, int>> m_rent;
	unordered_map<std::pair<int,int>, int, SPosHash> m_mPrice;
};

扩展阅读

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关推荐

我想对大家说的话
喜缺全书算法册》以原理、正确性证明、总结为主。
按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闻缺陷则喜何志丹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值