【对顶堆 优先队列】2102. 序列顺序查询

本文涉及知识点

对顶堆 优先队列

LeetCode 2102. 序列顺序查询

一个观光景点由它的名字 name 和景点评分 score 组成,其中 name 是所有观光景点中 唯一 的字符串,score 是一个整数。景点按照最好到最坏排序。景点评分 越高 ,这个景点越好。如果有两个景点的评分一样,那么 字典序较小 的景点更好。
你需要搭建一个系统,查询景点的排名。初始时系统里没有任何景点。这个系统支持:
添加 景点,每次添加 一个 景点。
查询 已经添加景点中第 i 好 的景点,其中 i 是系统目前位置查询的次数(包括当前这一次)。
比方说,如果系统正在进行第 4 次查询,那么需要返回所有已经添加景点中第 4 好的。
注意,测试数据保证 任意查询时刻 ,查询次数都 不超过 系统中景点的数目。

请你实现 SORTracker 类:

SORTracker() 初始化系统。
void add(string name, int score) 向系统中添加一个名为 name 评分为 score 的景点。
string get() 查询第 i 好的景点,其中 i 是目前系统查询的次数(包括当前这次查询)。

示例:

输入:
[“SORTracker”, “add”, “add”, “get”, “add”, “get”, “add”, “get”, “add”, “get”, “add”, “get”, “get”]
[[], [“bradford”, 2], [“branford”, 3], [], [“alps”, 2], [], [“orland”, 2], [], [“orlando”, 3], [], [“alpine”, 2], [], []]
输出:
[null, null, null, “branford”, null, “alps”, null, “bradford”, null, “bradford”, null, “bradford”, “orland”]

解释:
SORTracker tracker = new SORTracker(); // 初始化系统
tracker.add(“bradford”, 2); // 添加 name=“bradford” 且 score=2 的景点。
tracker.add(“branford”, 3); // 添加 name=“branford” 且 score=3 的景点。
tracker.get(); // 从好带坏的景点为:branford ,bradford 。
// 注意到 branford 比 bradford 好,因为它的 评分更高 (3 > 2) 。
// 这是第 1 次调用 get() ,所以返回最好的景点:“branford” 。
tracker.add(“alps”, 2); // 添加 name=“alps” 且 score=2 的景点。
tracker.get(); // 从好到坏的景点为:branford, alps, bradford 。
// 注意 alps 比 bradford 好,虽然它们评分相同,都为 2 。
// 这是因为 “alps” 字典序 比 “bradford” 小。
// 返回第 2 好的地点 “alps” ,因为当前为第 2 次调用 get() 。
tracker.add(“orland”, 2); // 添加 name=“orland” 且 score=2 的景点。
tracker.get(); // 从好到坏的景点为:branford, alps, bradford, orland 。
// 返回 “bradford” ,因为当前为第 3 次调用 get() 。
tracker.add(“orlando”, 3); // 添加 name=“orlando” 且 score=3 的景点。
tracker.get(); // 从好到坏的景点为:branford, orlando, alps, bradford, orland 。
// 返回 “bradford”.
tracker.add(“alpine”, 2); // 添加 name=“alpine” 且 score=2 的景点。
tracker.get(); // 从好到坏的景点为:branford, orlando, alpine, alps, bradford, orland 。
// 返回 “bradford” 。
tracker.get(); // 从好到坏的景点为:branford, orlando, alpine, alps, bradford, orland 。
// 返回 “orland” 。

提示:

name 只包含小写英文字母,且每个景点名字互不相同。
1 <= name.length <= 10
1 <= score <= 105
任意时刻,调用 get 的次数都不超过调用 add 的次数。
总共 调用 add 和 get 不超过 4 * 104

对顶堆

小根堆m_big记录最大的m_cnt的数,大根堆m_other记录余下的数。
m_cnt 初始为1,每get一次就+1。
get函数:
如果m_big的数量小于m_cnt,从m_other移到m_big。
m_cnt++
return m_big.top。
Add函数:
将当前数加到m_big中,如果m_big的数量大于m_cnt,移数据到m_other。
确保m_big的数大于m_other的数。
为了不重写小于号,可以直接将name倒序,利用pair自带的<。 结果此方法错误,比如:a z,倒序后,字典序没变。
将a,b,c ⋯ \cdots 变成 z y x ⋯ \cdots 也不性。
aa aac,转化后字典序没变。
最终还是重写了小于。
可以用笨方法(聪明方法):将分数乘以-1,然后小根堆换大根堆。

代码

核心代码

class CName {
public:
	CName(const std::string& str) {
		m_str = str;
	}
	bool operator<(const CName& n) const{
		return m_str > n.m_str;
	}
	std::string m_str;
};
class SORTracker {
public:
	SORTracker() {
	}
	void add(string name, int score) {
		m_big.emplace(make_pair(score, CName(name)));
		if (m_big.size() > m_cnt) {
			m_other.emplace(m_big.top());
			m_big.pop();
		}
		while (m_big.size() && m_other.size() && (m_big.top()< m_other.top())) {
			const auto b1 = m_big.top();
			const auto o1 = m_other.top();
			m_big.pop();
			m_other.pop();
			m_big.emplace(o1);
			m_other.emplace(b1);
		}
	}
	string get() {
		if (m_big.size() < m_cnt) {
			m_big.emplace(m_other.top());
			m_other.pop();
		}
		m_cnt++;
		return m_big.top().second.m_str;
	}
	int m_cnt = 1;
	priority_queue<pair<int, CName>, vector<pair<int, CName>>, greater<>> m_big;
	priority_queue < pair<int, CName>> m_other;
};

单元测试

template<class T1, class T2>
void AssertEx(const T1& t1, const T2& t2)
{
	Assert::AreEqual(t1, t2);
}

template<class T>
void AssertEx(const vector<T>& v1, const vector<T>& v2)
{
	Assert::AreEqual(v1.size(), v2.size());
	for (int i = 0; i < v1.size(); i++)
	{
		Assert::AreEqual(v1[i], v2[i]);
	}
}

template<class T>
void AssertV2(vector<vector<T>> vv1, vector<vector<T>> vv2)
{
	sort(vv1.begin(), vv1.end());
	sort(vv2.begin(), vv2.end());
	Assert::AreEqual(vv1.size(), vv2.size());
	for (int i = 0; i < vv1.size(); i++)
	{
		AssertEx(vv1[i], vv2[i]);
	}
}

namespace UnitTest
{
	int k;
	vector<int> arrival,load;
	TEST_CLASS(UnitTest)
	{
	public:
		TEST_METHOD(TestMethod00)
		{
			SORTracker tracker; // 初始化系统
			tracker.add("bradford", 2); // 添加 name="bradford" 且 score=2 的景点。
			tracker.add("branford", 3); // 添加 name="branford" 且 score=3 的景点。
			AssertEx(string("branford"),tracker.get());              // 从好带坏的景点为:branford ,bradford 。
										// 注意到 branford 比 bradford 好,因为它的 评分更高 (3 > 2) 。
										// 这是第 1 次调用 get() ,所以返回最好的景点:"branford" 。
			tracker.add("alps", 2);     // 添加 name="alps" 且 score=2 的景点。
			AssertEx(string("alps"), tracker.get()); ;              // 从好到坏的景点为:branford, alps, bradford 。
										// 注意 alps 比 bradford 好,虽然它们评分相同,都为 2 。
										// 这是因为 "alps" 字典序 比 "bradford" 小。
										// 返回第 2 好的地点 "alps" ,因为当前为第 2 次调用 get() 。
			tracker.add("orland", 2);   // 添加 name="orland" 且 score=2 的景点。
			AssertEx(string("bradford"), tracker.get());              // 从好到坏的景点为:branford, alps, bradford, orland 。
										// 返回 "bradford" ,因为当前为第 3 次调用 get() 。
			tracker.add("orlando", 3);  // 添加 name="orlando" 且 score=3 的景点。
			AssertEx(string("bradford"), tracker.get());               // 从好到坏的景点为:branford, orlando, alps, bradford, orland 。
										// 返回 "bradford".
			tracker.add("alpine", 2);   // 添加 name="alpine" 且 score=2 的景点。
			AssertEx(string("bradford"), tracker.get());            // 从好到坏的景点为:branford, orlando, alpine, alps, bradford, orland 。
										// 返回 "bradford" 。
			AssertEx(string("orland"), tracker.get());             // 从好到坏的景点为:branford, orlando, alpine, alps, bradford, orland 。
										// 返回 "orland" 。
		}
		TEST_METHOD(TestMethod01)
		{
			SORTracker tracker; // 初始化系统
			tracker.add("a", 10000);
			tracker.add("z", 1);
			AssertEx(string("a"), tracker.get());
			tracker.add("b", 10000);
			AssertEx(string("b"), tracker.get());
			AssertEx(string("z"), tracker.get());
		}

	};
}

简洁代码

class SORTracker {
public:
	SORTracker() {
	}
	void add(string name, int score) {
		m_big.emplace(make_pair(score, CName(name)));
		m_other.emplace(m_big.top());
		m_big.pop();
	}
	string get() {
		m_big.emplace(m_other.top());
		m_other.pop();
		return m_big.top().second.m_str;
	}	
	priority_queue<pair<int, CName>, vector<pair<int, CName>>, greater<>> m_big;
	priority_queue < pair<int, CName>> m_other;
};

用set模拟

class SORTracker {
public:
	SORTracker() {
		m_other.emplace(0, "");
		m_it = m_other.begin();
	}
	void add(string name, int score) {
		auto tmp = make_pair(score, CName(name));
		m_other.emplace(tmp);
		if (tmp > *m_it) {
			m_it--;
		}
	}
	string get() {
		return (m_it++)->second.m_str;
	}	
	set < pair<int, CName>, greater<>>::iterator m_it;
	set < pair<int, CName>,greater<>> m_other;
};

扩展阅读

视频课程

先学简单的课程,请移步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++**实现。

相关推荐

  1. 顺序实现

    2024-07-17 07:44:02       35 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-17 07:44:02       70 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-17 07:44:02       74 阅读
  3. 在Django里面运行非项目文件

    2024-07-17 07:44:02       62 阅读
  4. Python语言-面向对象

    2024-07-17 07:44:02       72 阅读

热门阅读

  1. 嵌入式linux相机 摄像头模块

    2024-07-17 07:44:02       31 阅读
  2. 服务器网络配置

    2024-07-17 07:44:02       28 阅读
  3. [NOIP2006 提高组] 能量项链(含代码)

    2024-07-17 07:44:02       26 阅读
  4. VBA学习(20):一批简单的Excel VBA编程问题解答

    2024-07-17 07:44:02       28 阅读
  5. ubuntu下发布应用,ldd脚本代替linuxdeployqt

    2024-07-17 07:44:02       22 阅读
  6. 我们来科普以下vue中v-show 和v-if区别

    2024-07-17 07:44:02       25 阅读
  7. Day 10.08函数作业答案·二

    2024-07-17 07:44:02       24 阅读
  8. 面试题 30. 包含 min 函数的栈

    2024-07-17 07:44:02       26 阅读
  9. OpenResty使用Lua笔记

    2024-07-17 07:44:02       26 阅读
  10. Springboot定义阿里云oss工具类

    2024-07-17 07:44:02       26 阅读