【华为OD-E卷 - 热点网站统计 100分(python、java、c++、js、c)】
题目
企业路由器的统计页面,有一个功能需要动态统计公司访问最多的网页URL top N。请设计一个算法,可以高效动态统计Top N的页面
输入描述
- 每一行都是一个URL或一个数字,如果是URL,代表一段时间内的网页访问; 如果是一个数字N,代表本次需要输出的Top N个URL。
输入约束:
1、总访问网页数量小于5000个,单网页访问次数小于65535次; 2、网页URL仅由字母,数字和点分隔符组成,且长度小于等于127字节; 3、数字是正整数,小于等于10且小于当前总访问网页数
输出描述
- 每行输入要对应一行输出,输出按访问次数排序的前N个URL,用逗号分隔。
输出要求:
1、每次输出要统计之前所有输入,不仅是本次输入; 2、如果有访问次数相等的URL,按URL的字符串字典序升序排列,输出排序靠前的URL
用例
用例一:
输入:
news.qq.com
news.sina.com.cn
news.qq.com
news.qq.com
game.163.com
game.163.com
www.huawei.com
www.cctv.com
3
www.huawei.com
www.cctv.com
www.huawei.com
www.cctv.com
www.huawei.com
www.cctv.com
www.huawei.com
www.cctv.com
www.huawei.com
3
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
输出:
news.qq.com,game.163.com,news.sina.com.cn
www.huawei.com,www.cctv.com,news.qq.com
- 1
- 2
用例二:
输入:
news.qq.com
www.cctv.com
1
www.huawei.com
www.huawei.com
2
3
- 1
- 2
- 3
- 4
- 5
- 6
- 7
输出:
news.qq.com
www.huawei.com,news.qq.com
www.huawei.com,news.qq.com,www.cctv.com
- 1
- 2
- 3
python解法
- 解题思路:
- 这段代码实现了一个简单的 URL 计数器,能够实时统计 URL 的访问次数,并按要求输出访问次数最多的 URL。以下是具体功能和解题思路:
URL 统计功能:使用 Python 的 collections.Counter 数据结构对输入的 URL 进行计数。Counter 是一个专门用于计数的字典,键是 URL,值是对应 URL 出现的次数。
按条件输出:
如果输入的是一个数字 n,输出访问次数最高的前 n 个 URL。
如果输入的是一个 URL,则更新该 URL 的计数。
排序逻辑:
先按访问次数从高到低排序。
如果访问次数相同,则按 URL 的字典序排列。
输入与退出:
程序通过循环接受用户的输入。
遇到 EOFError(如用户使用 Ctrl+D 或 Ctrl+Z)时,退出程序
from collections import Counter # 导入 Counter 用于统计 URL 的出现次数
# 创建一个 Counter 对象,用于统计 URL 访问次数
url_counter = Counter()
# 定义一个函数,用于获取访问次数最多的前 n 个 URL
def get_top_n_urls(n):
# 将 URL 按访问次数降序排序,如果次数相同按字典序升序排列
sorted_urls = sorted(url_counter.items(), key=lambda x: (-x[1], x[0]))
# 提取前 n 个 URL,并用逗号连接成字符串返回
return ",".join(url for url, _ in sorted_urls[:n])
try:
# 循环不断读取用户输入
while True:
input_value = input().strip() # 去掉输入的前后空格
if input_value.isnumeric(): # 如果输入的是纯数字
# 将输入转换为整数并获取访问次数最多的前 n 个 URL
print(get_top_n_urls(int(input_value)))
else: # 如果输入的是一个字符串(假设是 URL)
# 更新该 URL 的访问次数
url_counter[input_value] += 1
except EOFError:
# 遇到 EOFError(如用户按 Ctrl+D 或 Ctrl+Z)时退出程序
pass
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
java解法
- 解题思路
- 这段代码实现了一个实时统计 URL 访问次数的功能,同时可以根据用户输入的数量 n 输出访问次数最多的前 n 个 URL。以下是解题步骤和逻辑:
数据存储与统计:
使用 TreeMap 存储 URL 及其对应的访问次数,TreeMap 会按键的字典序自动排序,方便管理和检索。
URL 的访问次数通过 getOrDefault 方法更新。
获取访问次数最多的 URL:
使用 PriorityQueue(优先队列)对 TreeMap 的 entrySet 进行排序。
排序规则:
优先按访问次数降序排列。
如果访问次数相同,则按 URL 的字典序升序排列。
最终输出按排序规则选取的前 n 个 URL。
输入处理:
如果输入是数字,调用 getTopN 方法输出结果。
如果输入是 URL,更新 URL 访问次数。
异常处理:
在 isNumeric 方法中捕获非数字输入的异常,确保程序不会因为非法输入而崩溃
import java.util.*;
public class Main {
// 用 TreeMap 存储 URL 和其访问次数,按字典序自动排序
static Map<String, Integer> urlCount = new TreeMap<>();
// 用 PriorityQueue 实现访问次数和字典序的自定义排序
static PriorityQueue<Map.Entry<String, Integer>> pq;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 循环读取用户输入
while (sc.hasNextLine()) {
String input = sc.nextLine();
// 如果输入是数字
if (isNumeric(input)) {
int n = Integer.parseInt(input); // 将输入转换为整数
System.out.println(getTopN(n)); // 获取访问次数最多的 n 个 URL
} else {
// 如果输入是 URL,更新其访问次数
urlCount.put(input, urlCount.getOrDefault(input, 0) + 1);
}
}
}
/**
* 获取访问次数最多的前 n 个 URL
*
* @param n 前 n 个 URL
* @return 按要求排序的前 n 个 URL,使用逗号分隔
*/
private static String getTopN(int n) {
// 定义优先队列,按访问次数降序排列,如果次数相同按字典序升序
pq = new PriorityQueue<>((a, b) -> {
if (!a.getValue().equals(b.getValue())) {
return b.getValue() - a.getValue(); // 按访问次数降序
} else {
return a.getKey().compareTo(b.getKey()); // 按字典序升序
}
});
// 将 TreeMap 中的所有条目加入优先队列
pq.addAll(urlCount.entrySet());
// 使用 StringJoiner 拼接结果
StringJoiner sj = new StringJoiner(",");
for (int i = 0; i < n && !pq.isEmpty(); i++) {
sj.add(pq.poll().getKey()); // 取出队列中最优先的 URL
}
return sj.toString();
}
/**
* 判断字符串是否为数字
*
* @param str 输入字符串
* @return 如果是数字返回 true,否则返回 false
*/
private static boolean isNumeric(String str) {
try {
Integer.parseInt(str); // 尝试将字符串转换为整数
return true;
} catch (NumberFormatException e) {
return false; // 转换失败说明不是数字
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
C++解法
- 解题思路
更新中
- 1
C解法
更新中
- 1
JS解法
数据结构选用:
使用对象 urlVisits 存储 URL 和对应的访问次数。
urlVisits 的键为 URL,值为该 URL 的访问次数。
输入处理:
如果输入是 URL,则更新 urlVisits 中对应 URL 的访问次数。
如果输入是数字,则按规则排序并输出访问次数最多的前 n 个 URL。
排序规则:
按访问次数降序排序。
如果访问次数相同,按字典序升序排序。
异步输入:
使用 Node.js 的 readline 模块实现异步输入,允许用户连续输入。
输出处理:
将排序后的前 n 个 URL 提取并用逗号拼接输出
// 使用 readline 模块处理用户输入
const readline = require("readline").createInterface({ input: process.stdin });
// 创建一个异步迭代器用于读取输入
const iterator = readline[Symbol.asyncIterator]();
// 定义一个异步函数来获取输入
const getInput = async () => (await iterator.next()).value;
(async function () {
// 用对象存储 URL 和访问次数
const urlVisits = {};
// 异步循环处理输入
while ((input = await getInput())) {
// 将输入尝试转换为数字
const number = parseInt(input);
if (isNaN(number)) {
// 如果输入不是数字,视为 URL,更新访问次数
urlVisits[input] = (urlVisits[input] ?? 0) + 1;
continue;
}
// 如果输入是数字,按规则排序并输出前 n 个 URL
const result = Object.entries(urlVisits) // 将对象转为 [key, value] 数组
.sort((first, second) =>
second[1] - first[1] || // 先按访问次数降序排序
first[0].localeCompare(second[0]) // 再按字典序升序排序
)
.slice(0, number) // 获取前 n 个元素
.map((item) => item[0]) // 提取 URL
.join(","); // 拼接成逗号分隔的字符串
console.log(result); // 输出结果
}
})();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
注意:
如果发现代码有用例覆盖不到的情况,欢迎反馈!会在第一时间修正,更新。
解题不易,如对您有帮助,欢迎点赞/收藏
评论记录:
回复评论: