【华为OD-E卷 - 字符统计及重排 100分(python、java、c++、js、c)】

embedded/2025/3/18 13:43:37/

pythonjavacjsc_0">【华为OD-E卷 - 字符统计及重排 100分(pythonjava、c++、js、c)】

题目

给出一个仅包含字母的字符串,不包含空格,统计字符串中各个字母(区分大小写)出现的次数,并按照字母出现次数从大到小的顺序。
输出各个字母及其出现次数。如果次数相同,按照自然顺序进行排序,且小写字母在大写字母之前

输入描述

  • 输入一行,为一个仅包含字母的字符串

输出描述

  • 按照字母出现次数从大到小的顺序输出各个字母和字母次数,用英文分号分隔,注意末尾的分号;

字母和次数间用英文冒号分隔

用例

用例一:
输入:
xyxyXX
输出:
x:2;y:2;X:2;
用例二:
输入:
abababb
输出:
b:4;a:3;

python_50">python解法

  • 解题思路:
  • 统计字符频次:

通过遍历输入字符串 text,使用字典 freq 统计每个字符的出现次数。
字典的键是字符,值是该字符的出现次数。
自定义排序:

使用 compare(x, y) 函数自定义排序规则:
第一优先级:按照字符出现次数降序排序(出现次数多的排前面)。
第二优先级:如果两个字符出现次数相同,按以下规则比较:
同类字符(均为小写或均为大写):按字典序升序排序。
不同类字符(一个大写、一个小写):小写字母排在前面,大写字母排在后面。
排序并格式化输出:

使用 sorted() 函数,将字符频次字典转换为列表并按 compare 规则排序。
通过列表推导式将排序后的字符频次转换为格式 字符:次数; 形式的字符串

使用到的算法
哈希表(字典):用于统计字符频次,时间复杂度为 O(n)(n 为字符串长度)。
自定义排序(基于 cmp_to_key 的比较器):
基于比较器的排序(cmp_to_key):时间复杂度 O(m log m),其中 m 为不同字符的数量。
排序规则:
先按出现次数降序排列。
频次相同情况下:
同类型字符(大写或小写):按字典序升序排列。
不同类型字符(小写优先)。
字符串拼接:遍历排序后的列表并拼接结果,时间复杂度 O(m)

python">import functools# 获取输入字符串
text = input()def compare(x, y):"""自定义比较函数,用于排序字符频次表:param x: (字符, 频次) 元组1:param y: (字符, 频次) 元组2:return: 负数(x < y), 0(相等), 正数(x > y)"""# 1. 先按出现次数降序排序if x[1] != y[1]:return y[1] - x[1]# 2. 处理相同频次的字符:#    - 同类型字符(都小写或都大写),按字典序升序排列if (x[0].islower() and y[0].islower()) or (x[0].isupper() and y[0].isupper()):return 1 if x[0] > y[0] else -1# 3. 小写字母排在前面,大写字母排在后面return 1 if x[0].isupper() else -1def result():"""计算字符频次,并按规则排序后格式化输出:return: 格式化的结果字符串"""# 1. 统计字符频次freq = {}for ch in text:freq[ch] = freq.get(ch, 0) + 1# 2. 将字典转换为 (字符, 频次) 元组列表freq_list = list(freq.items())# 3. 使用自定义排序函数进行排序freq_list.sort(key=functools.cmp_to_key(compare))# 4. 拼接结果字符串return "".join([f"{k}:{v};" for k, v in freq_list])# 输出结果
print(result())

java_129">java解法

  • 解题思路
  • 字符频次统计

读取用户输入的字符串 input。
使用 TreeMap<Character, Integer> 统计字符串中各字符的出现次数:
TreeMap 具有自动排序功能,默认按照 字典序 排序键(字符)。
自定义排序

使用 PriorityQueue 进行 自定义排序:
第一优先级:按出现次数降序排序(频次越高,优先级越高)。
第二优先级(出现次数相同时):
若两个字符 均为小写 或 均为大写,按字典序升序排列。
若一个字符为 小写,另一个为 大写,小写优先,大写在后。
格式化输出

依次从 PriorityQueue 取出字符及其出现次数,拼接成 字符:次数; 的格式字符串并返回

用到的算法
哈希表(TreeMap):

用于 统计字符频次,时间复杂度为 O(n)(n 为字符串长度)。
由于 TreeMap 自动排序,默认 字典序 排序键(字符),但不影响自定义排序。
优先队列(PriorityQueue):

维护一个 最大堆 进行 自定义排序,用于 按照频次降序排列,时间复杂度 O(m log m)(m 为不同字符数)。
排序规则:
按字符出现次数降序。
出现次数相同:
同类字符(均小写/均大写) 按 字典序升序 排列。
小写字母优先,大写字母在后。
字符串拼接(StringBuilder):

由于 Java 中字符串拼接 String 需要新建对象,因此用 StringBuilder 优化。
复杂度 O(m)

java">import java.util.*;public class Main {public static void main(String[] args) {// 读取输入字符串Scanner scanner = new Scanner(System.in);String input = scanner.nextLine();scanner.close();// 计算字符频次并输出结果System.out.println(calculateFrequency(input));}public static String calculateFrequency(String input) {// 1. 使用 TreeMap 统计字符频次,并按照字典序自动排序TreeMap<Character, Integer> charCountMap = new TreeMap<>();for (char ch : input.toCharArray()) {charCountMap.put(ch, charCountMap.getOrDefault(ch, 0) + 1);}// 2. 使用优先队列(最大堆),根据自定义规则排序PriorityQueue<Map.Entry<Character, Integer>> queue = new PriorityQueue<>((a, b) -> {// (1) 先按照字符出现次数降序排列if (!a.getValue().equals(b.getValue())) {return b.getValue() - a.getValue();} // (2) 出现次数相同时,按以下规则排序:else {// (2.1) 如果两个字符都是小写或都是大写,按字典序升序排序if (Character.isLowerCase(a.getKey()) && Character.isLowerCase(b.getKey())) {return a.getKey() - b.getKey();} if (Character.isUpperCase(a.getKey()) && Character.isUpperCase(b.getKey())) {return a.getKey() - b.getKey();}// (2.2) 小写字母优先,大写字母在后return Character.isLowerCase(a.getKey()) ? -1 : 1;}});// 3. 将统计结果放入优先队列queue.addAll(charCountMap.entrySet());// 4. 依次取出排序后的字符和频次,拼接结果字符串StringBuilder result = new StringBuilder();while (!queue.isEmpty()) {Map.Entry<Character, Integer> entry = queue.poll();result.append(entry.getKey()).append(":").append(entry.getValue()).append(";");}// 5. 返回格式化字符串return result.toString();}
}

C++解法

  • 解题思路
  • 字符频次统计

读取输入字符串 input。
使用 map<char, int>(有序映射) 统计各字符的出现次数:
键(char)为字符,值(int)为出现次数。
map 默认按照 字典序排序 键(字符)。
自定义排序

将 map 转换为 vector<pair<char, int>>,以便使用 sort() 自定义排序:
第一优先级:按出现次数降序排序(频次高的字符排前)。
第二优先级(出现次数相同时):
小写字母优先(islower())。
同类字符(均为小写或均为大写) 按 字典序升序 排序。
格式化输出

遍历排序后的 vector,拼接成 字符:次数; 格式的字符串

使用到的算法
哈希表(map):

统计字符频次,时间复杂度 O(n)(n 为字符串长度)。
map 采用 红黑树(RB-Tree) 实现,插入元素的复杂度 O(log m),m 为不同字符数。
自定义排序(sort() + lambda):

排序优先级:
按频次降序(O(m log m))。
频次相同:
小写字母优先。
同类字符(小写/大写) 按 字典序升序。
字符串拼接(stringstream):

stringstream 处理拼接,避免 string 频繁 + 操作(O(m))

#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <sstream>using namespace std;/*** 计算字符频次并进行排序* @param input 输入字符串* @return 格式化后的频次字符串*/
string calculateFrequency(const string& input) {// 1. 使用 map 统计字符出现次数(按字典序自动排序)map<char, int> charCountMap;for (char ch : input) {charCountMap[ch]++;}// 2. 将 map 转换为 vector,便于自定义排序vector<pair<char, int>> entryList(charCountMap.begin(), charCountMap.end());// 3. 自定义排序sort(entryList.begin(), entryList.end(), [](const pair<char, int>& a, const pair<char, int>& b) {// (1) 先按出现次数降序排序if (b.second != a.second) {return b.second < a.second; // 频次高的排前面}// (2) 频次相同情况下:// 小写字母优先if (islower(a.first) && isupper(b.first)) {return true;}if (isupper(a.first) && islower(b.first)) {return false;}// 同类型字符(小写或大写)按字典序升序return a.first < b.first;});// 4. 拼接结果字符串stringstream result;for (size_t i = 0; i < entryList.size(); ++i) {result << entryList[i].first << ":" << entryList[i].second;if (i != entryList.size() - 1) {result << ";";}}return result.str() + ";";
}int main() {// 读取输入字符串string input;getline(cin, input);// 输出计算结果cout << calculateFrequency(input) << endl;return 0;
}

C解法

  • 解题思路

更新中

JS解法

  • 解题思路

  • 字符频次统计

读取用户输入的字符串 s。
使用 Map 统计各字符的出现次数:
Map 的键是字符,值是该字符的出现次数。
自定义排序

将 Map 转换为数组,使用 sort() 进行 自定义排序:
第一优先级:按出现次数降序排序(频次高的字符排前)。
第二优先级(出现次数相同时):
若两个字符 同为小写或同为大写,按 字典序升序 排序(localeCompare())。
若 一个大写、一个小写,小写字母排前,大写字母排后。
格式化输出

遍历排序后的数组,将字符及其出现次数拼接成 字符:次数; 格式的字符串

使用到的算法
哈希表(Map):

用于统计字符频次,时间复杂度 O(n)(n 为字符串长度)。
Map 适用于 动态插入和查询。
自定义排序(sort() + 比较函数):

排序优先级:
按出现次数降序(O(m log m))。
频次相同时:
同类字符(小写/大写) 按 字典序升序(localeCompare())。
小写字母优先,大写字母在后。
字符串拼接(map().join(‘’)):

遍历排序数组并拼接字符串,时间复杂度 O(m)

javascript">const readline = require("readline");// 创建标准输入/输出接口
const rl = readline.createInterface({input: process.stdin,output: process.stdout,
});// 监听标准输入,读取用户输入并计算结果
rl.on("line", (line) => {console.log(getResult(line));
});/*** 计算字符频次,并进行自定义排序后格式化输出* @param {string} s - 输入字符串* @return {string} - 频次统计后的格式化字符串*/
function getResult(s) {// 1. 统计字符频次const countMap = new Map();for (let char of s) {countMap.set(char, (countMap.get(char) || 0) + 1);}// 2. 将 Map 转换为数组,并进行排序const sortedArr = Array.from(countMap).sort((a, b) => {// (1) 先按出现次数降序排列if (a[1] !== b[1]) {return b[1] - a[1];}// (2) 频次相同时:// (2.1) 同类型字符(都小写或都大写),按字典序升序if (isSameCase(a[0], b[0])) {return a[0].localeCompare(b[0]);}// (2.2) 小写字母优先,大写字母在后return isUpper(a[0]) ? 1 : -1;});// 3. 格式化输出,拼接字符串return sortedArr.map(([char, count]) => `${char}:${count};`).join('');
}/*** 判断两个字符是否是相同类型(均为大写或均为小写)* @param {string} a - 字符1* @param {string} b - 字符2* @return {boolean} - 是否同为大小写*/
function isSameCase(a, b) {return (isUpper(a) && isUpper(b)) || (isLower(a) && isLower(b));
}/*** 判断字符是否为小写字母* @param {string} letter - 字符* @return {boolean} - 是否为小写字母*/
function isLower(letter) {return letter >= "a" && letter <= "z";
}/*** 判断字符是否为大写字母* @param {string} letter - 字符* @return {boolean} - 是否为大写字母*/
function isUpper(letter) {return letter >= "A" && letter <= "Z";
}

注意:

如果发现代码有用例覆盖不到的情况,欢迎反馈!会在第一时间修正,更新。
解题不易,如对您有帮助,欢迎点赞/收藏


http://www.ppmy.cn/embedded/173604.html

相关文章

使用htool工具导出和导入Excel表

htool官网 代码中用到的hool包里面的excel工具ExcelUtil 1. 引入依赖 <!-- Java的工具类 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.25</version></dependency>&l…

正则表达式的基本应用以及查询工具

首先&#xff0c;是对于基本的正则表达式的应用以及部分介绍(见代码注释部分): 以javaScript为例 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-wi…

算法刷题整理合集(四)

本篇博客旨在记录自已的算法刷题练习成长&#xff0c;里面注有详细的代码注释以及和个人的思路想法&#xff0c;希望可以给同道之人些许帮助。本人也是算法小白&#xff0c;水平有限&#xff0c;如果文章中有什么错误或遗漏之处&#xff0c;望各位可以在评论区指正出来&#xf…

力扣hot100二刷——二叉树

第二次刷题不在idea写代码&#xff0c;而是直接在leetcode网站上写&#xff0c;“逼”自己掌握常用的函数。 标志掌握程度解释办法⭐Fully 完全掌握看到题目就有思路&#xff0c;编程也很流利⭐⭐Basically 基本掌握需要稍作思考&#xff0c;或者看到提示方法后能解答⭐⭐⭐Sl…

高级java每日一道面试题-2025年3月04日-微服务篇[Eureka篇]-Eureka是什么?

如果有遗漏,评论区告诉我进行补充 面试官: Eureka是什么&#xff1f; 我回答: 在Java高级面试中&#xff0c;关于Eureka的讨论通常会涵盖其基本概念、组件与架构、工作原理、高级特性以及与其他服务发现工具的比较等多个方面。以下是结合提供的内容对Eureka进行的详细解析和…

Python 鼠标轨迹算法 - 防止游戏检测

一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序&#xff0c;它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言&#xff0c;原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势&#xff1a; 模拟…

C++特性——智能指针

为什么需要智能指针 对于定义的局部变量&#xff0c;当作用域结束之后&#xff0c;就会自动回收&#xff0c;这没有什么问题。 当时用new delete的时候&#xff0c;就是动态分配对象的时候&#xff0c;如果new了一个变量&#xff0c;但却没有delete&#xff0c;这会造成内存泄…

每日学习Java之一万个为什么

场景启动器&#xff1a;starter 参考常见启动器 默认配置 官网默认值 依赖 见官网 / pom父依赖 注解 SpringBootApplication&#xff1a;启动自动装配&#xff0c;配合 main SpringApplication.run&#xff08;.class,args&#xff09; SpringBootTest&#xff1a;Spri…