本文涉及知识点
对顶堆 优先队列
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++**实现。











