1055. The World's Richest (25)

本文介绍了一种高效处理大量用户数据查询的算法。通过预先排序用户数据并构建年龄范围索引,结合使用小根堆来筛选出指定条件下的高净值用户,解决了大数据量下查询效率的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.先把用户按照年龄大小排序,因为后面给出的是年龄范围,所以需要快速找出符合年龄要求的用户

2.建立一个年龄数组,该数组记录了以年龄x为左界时,用户数组的idx,以年龄x为右界时,用户数组的idx,通过年龄数组,就可以快速定位到用户数组的对应位置

3.刚开始,在查询输入时,直接定位到用户数组,把对应的用户数组段复制出来,进行排序,但是会超时(卡了还挺久的),然后仔细思考,发现用户数组的数量可能很大,<=100000,查询数量最大为2000,假如每次都复制100000,然后再进行排序,会严重浪费时间。

4.再观察题目,发现最终需要显示的数量最多只有100个,于是考虑建立一个小根堆,把它的大小维持在需要显示的数量showSum,最后复制输出即可。

为什么建立小根堆?我们的目的是要找出财富值最大的showSum个用户,建立小根堆,堆顶为showSum个用户中财富最小的,假如遍历用户j,发现用户j的财富值比小根堆的堆顶要大,那么把用户压入小根堆,再从小根堆中弹出堆顶即可。





AC代码:

//#include<string>
//#include<stack>
//#include<unordered_set>
//#include <sstream>
//#include "func.h"
//#include <list>
#include <iomanip>
#include<unordered_map>
#include<set>
#include<queue>
#include<map>
#include<vector>
#include <algorithm>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
#include<stack>
using namespace std;
struct PeopleNode{
	int age, netWorth;
	char name[9];
	PeopleNode() :age(-1), netWorth(-1){};
};

bool cmp(const PeopleNode&a, const PeopleNode&b)
{//根据年龄排序
	if (a.age < b.age)
		return true;
	else
		return false;
}
struct cmpHeap{//根据题目的显示规则排序
	bool operator()(const PeopleNode&a, const PeopleNode&b)
	{
		if (a.netWorth > b.netWorth)
			return true;
		else if (a.netWorth == b.netWorth && a.age < b.age)
			return true;
		else if (a.netWorth == b.netWorth && a.age == b.age)
		{
			int asize = 0, bsize = 0;
			for (int i = 0; i < 9; i++)
			{
				if (a.name[i] != 0)
					asize++;
				else
					break;
			}
			for (int i = 0; i < 9; i++)
			{
				if (b.name[i] != 0)
					bsize++;
				else
					break;
			}
			for (int i = 0; i < min(asize, bsize); i++)
			{
				if (a.name[i] < b.name[i])
					return true;
				else if (a.name[i] > b.name[i])
					return false;
			}
			if (asize < bsize) return true;
			else return false;
		}
		else
			return false;
	}
};



int main(void)
{
	int peopleSum, querySum;
	scanf("%d %d", &peopleSum, &querySum);
	vector<PeopleNode> people(peopleSum);
	vector<vector<PeopleNode>> agePeople(201);
	for (int i = 0; i < peopleSum; i++)
	{
		scanf("%s %d %d", people[i].name, &people[i].age, &people[i].netWorth);
	}

	sort(people.begin(), people.end(), cmp);
	vector<pair<int, int>> ageRange(201, { -1, -1 });
	int idx = 0;

	//计算年龄范围数组
	for (int i = 0; i < ageRange.size(); i++)
	{
		if (idx < people.size())//确保idx在size内
		{
			if (idx == 0 && people[idx].age > i)
			{//idx不进行++,而i++,直到i和age相等
				ageRange[i].first = 0;
				ageRange[i].second = -1;//以-1作为右边界,意思是不存在年龄小于等于i的人
			}
			else if (idx != 0 && people[idx].age > i)
			{//idx不进行++,而i++,直到i和age相等
				ageRange[i].first = idx;//i岁的搜索的起始idx,以idx作为左边界
				ageRange[i].second = idx - 1;//i岁的搜索的终止idx,以idx-1作为右边界
			}
			else if (people[idx].age == i)
			{//如果i等于年龄
				ageRange[i].first = idx;
				while (idx < people.size() && people[idx].age == i)
				{//一直到age和i不相等
					idx++;
				}
				ageRange[i].second = idx - 1;//第idx个人的年龄不等于i,第idx-1个人的年龄等于i
			}
		}
		else if (i>0)
		{//如果i的值大于0,且idx超出范围(即已经遍历完用户)
			ageRange[i].first = people.size();//把i的左界设置为无效值
			ageRange[i].second = ageRange[i - 1].second;//把i的右界设置为用户idx的最大值
		}
	}

	for (int i = 0; i < querySum; i++)
	{
		int showSum, minA, maxA;
		scanf("%d %d %d", &showSum, &minA, &maxA);
		int sum = ageRange[maxA].second - ageRange[minA].first + 1;//求出以minA为左界,maxA为右界的people数量
		printf("Case #%d:\n", i + 1);
		if (sum > 0)
		{//存在用户,sum的数量可能很大,用户取值<=100000,但是需要显示的数量<=100,所以用一个小根堆来维护需要显示的人
			vector<PeopleNode>::iterator ite = people.begin();
			priority_queue<PeopleNode, vector<PeopleNode>, cmpHeap> q;
			for (int j = 0; j < sum; j++)
			{
				if (q.size() == showSum && q.top().netWorth <= (ite + j + ageRange[minA].first)->netWorth)
				{//如果小根堆的数量已经达到显示数量,但是小根堆的顶部财富小于等于当前遍历的财富值,则压入
					q.push(*((ite + j + ageRange[minA].first)));
					q.pop();//相应地,弹出一个
				}
				else if (q.size()<showSum)//如果小根堆还没满,直接压入即可
					q.push(*((ite + j + ageRange[minA].first)));

			}
			vector<PeopleNode> show(min(showSum, (int)q.size()));
			for (int j = show.size() - 1; j >= 0; j--)
			{//因为需要升序排列,用的是小根堆,所以把小根堆的堆顶放在数组尾部
				show[j] = q.top();
				q.pop();
			}
			for (int j = 0; j < show.size(); j++)
			{
				printf("%s %d %d\n", show[j].name, show[j].age, show[j].netWorth);
			}
		}
		else
		{//数量小于等于0,直接输出None
			printf("None\n");
			sum = 0;
		}

	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值