URAL 1542: Autocompletion

本文介绍了一种基于Trie树的数据结构实现的算法,该算法用于高效地查找具有特定前缀的高频词汇。适用于处理大规模文本数据集,如搜索引擎、推荐系统等场景。文章详细解释了两种解决方案,并提供了完整的C++代码实现。

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

链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=31480

题意:给n个单词及其出现的频率,给m个前缀,找出一次为前缀的单词中频率为前10的。数据范围:1<=n<=10^5,1<=m<=15000,每个单词长度不超过15。

题解:做法一:trie树,维护一个vector<int> ans来记录结果。先对n个单词用先按频率排序,频率相同按字典序排序。然后将这m个前缀插入trie树中。然后将n个单词插入trie树。在插入的时候记得更新每个节点的ans。如果ans.size()>=10就不更新了。因为这n个单词已经排好序了。对于一这个节点为前缀的频率前10的字符串一定先插入字典树。。然后输出即可。

做法二:Hash+二分。先坑着~~~~~~。。。

代码君:

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;

const int maxn = 16;

struct Data {
	char str[maxn];
	int fre;
};

struct Node {
	Node *next[26];
	vector<int> ans;
	int cnt;
};

int tot;
Data data[100100];
Node pool[15555*maxn], *root;

bool cmp(int a, int b) {
	if (data[a].fre != data[b].fre)
		return data[a].fre > data[b].fre;
	return strcmp(data[a].str, data[b].str) < 0;
}

Node *newNode() {
	Node *p = &pool[tot++];
	memset(p->next, 0, sizeof(p->next));
	p->ans.clear();
	p->cnt = 0;
	return p;
}

void init() {
	tot = 0;
	root = newNode();
}

void insert(char buf[]) {
	Node *cur = root;
	for (int i = 0; buf[i]; i++) {
		int ch = buf[i] - 'a';
		if (!cur->next[ch])
			cur->next[ch] = newNode();
		cur = cur->next[ch];
	}
}

void query(char buf[], int id) {
	Node *cur = root;
	for (int i = 0; buf[i]; i++) {
		int ch = buf[i] - 'a';
		if (!cur->next[ch])
			return ;
		cur = cur->next[ch];
		if (cur->ans.size() >= 10)
			continue;
		cur->ans.push_back(id);
	}
}

void output(char buf[]) {
	Node *cur = root;
	for (int i = 0; buf[i]; i++) {
		int ch = buf[i] - 'a';
		cur = cur->next[ch];
	}
	for (int i = 0; i < cur->ans.size(); i++)
		printf("%s\n", data[cur->ans[i]].str);
}

int n, k, idx[100010];
char buf[15555][maxn];

void input() {
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		scanf("%s %d", data[i].str, &data[i].fre);
		idx[i] = i;
	}
	sort(idx, idx + n, cmp);
	init();
	scanf("%d", &k);
	for (int i = 0; i < k; i++) {
		scanf("%s", buf[i]);
		insert(buf[i]);
	}
}

void solve() {
	input();
	for (int i = 0; i < n; i++)
		query(data[idx[i]].str, idx[i]);
	for (int i = 0; i < k; i++) {
		if (i) puts("");
		output(buf[i]);
	}
}

int main() {
	solve();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值