#P3067. 字符统计及重排(100分)
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 207
            Accepted: 49
            Difficulty: 3
            
          
          
          
                       所属公司 : 
                              华为od
                                
            
                      
          
 
- 
                        算法标签>排序算法          
 
字符统计及重排(100分)
题面描述:
请编写一个程序,统计输入字符串中各个字母(区分大小写)出现的次数,并按照字母出现次数从大到小的顺序输出结果。如果出现次数相同,则按照字母的自然顺序排序,且小写字母排在大写字母之前。输出格式要求为每个字母及其出现次数用英文冒号分隔,各组之间用英文分号分隔,且末尾也需要有分号。
思路:
按照题意排序即可,先按照出现次数多少来排序,次数一样时优先小写字母并且优先ASCII码小的排序。
题解
- 
输入和输出:
- 输入:一个仅包含字母的字符串(不含空格)。
 - 输出:按照字母出现次数从大到小的顺序,每个字母及其出现次数用英文冒号分隔,各组之间用英文分号分隔,末尾也需要有分号。
 
 - 
步骤分析:
- 字符计数:使用一个 
map<char, int>来统计字符串中每个字母的出现次数。这里,字母作为键,出现次数作为值。 - 存储数据:将 
map中的键值对存储到一个vector<pair<char, int>>中,以便进行排序。 - 排序规则:
- 首先,根据字母的出现次数进行降序排序。
 - 如果出现次数相同,则比较字母的 ASCII 值,确保小写字母排在大写字母之前。
 - 在比较相同字母时,保持原有顺序。
 
 
 - 字符计数:使用一个 
 - 
排序实现:
- 使用 
std::sort对vector进行排序,并定义自定义的比较函数。该函数首先比较次数,其次处理字母的大小写优先级。 
 - 使用 
 - 
输出结果:
- 遍历排序后的 
vector,按照要求格式输出结果,确保每个部分之间用分号分隔,并在末尾添加一个分号。 
 - 遍历排序后的 
 
cpp
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
    string input;
    cin >> input;  // 读取输入字符串
    map<char, int> countMap;  // 用于存储字母及其出现次数
    // 统计字母出现次数
    for (char ch : input) {
        countMap[ch]++;
    }
    // 将字母及其次数存入 vector 中,以便排序
    vector<pair<char, int>> countVec(countMap.begin(), countMap.end());
    // 自定义排序规则
    sort(countVec.begin(), countVec.end(), [](const pair<char, int>& a, const pair<char, int>& b) {
        if (a.second != b.second) {
            return a.second > b.second;  // 按出现次数降序
        }
        // 次数相同,小写字母在前,大写字母在后
        if (a.first == b.first) {
            return false;  // 相同的字母保持原顺序
        }
        // 这里用简单的条件来确保小写在前
        return (isupper(a.first) && islower(b.first)) ? false : (islower(a.first) && isupper(b.first)) ? true : a.first < b.first;
    });
    // 输出结果
    for (const auto& p : countVec) {
        cout << p.first << ":" << p.second << ";";
    }
    return 0;
}
python
import functools
# 输入获取
s = input()
def cmp(a, b):
    # 首先根据出现次数进行比较
    if a[1] != b[1]:
        return b[1] - a[1]
    # 若出现次数相同,按字母的自然顺序进行排序
    if (a[0].islower() and b[0].islower()) or (a[0].isupper() and b[0].isupper()):
        return (a[0] > b[0]) - (a[0] < b[0])  # 自然顺序比较
    else:
        return (a[0].isupper() > b[0].isupper()) - (a[0].isupper() < b[0].isupper())  # 小写优先
# 算法入口
def getResult():
    letter = {}
    # 统计字母出现次数
    for c in s:
        letter[c] = letter.get(c, 0) + 1
    letterList = list(letter.items())
    # 使用自定义比较函数进行排序
    letterList.sort(key=functools.cmp_to_key(cmp))
    # 生成输出字符串
    return "".join(f"{x[0]}:{x[1]};" for x in letterList)
# 算法调用
print(getResult())
java
import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String s = scanner.nextLine();  // 输入获取
        System.out.println(getResult(s));  // 调用结果函数
    }
    // 自定义比较器
    private static Comparator<Map.Entry<Character, Integer>> cmp = new Comparator<Map.Entry<Character, Integer>>() {
        @Override
        public int compare(Map.Entry<Character, Integer> a, Map.Entry<Character, Integer> b) {
            // 首先根据出现次数进行比较
            if (!a.getValue().equals(b.getValue())) {
                return b.getValue().compareTo(a.getValue());
            }
            // 若出现次数相同,按字母的自然顺序进行排序
            if (Character.isLowerCase(a.getKey()) && Character.isLowerCase(b.getKey()) ||
                Character.isUpperCase(a.getKey()) && Character.isUpperCase(b.getKey())) {
                return a.getKey().compareTo(b.getKey());  // 自然顺序比较
            } else {
                return Character.isUpperCase(a.getKey()) ? 1 : -1;  // 小写优先
            }
        }
    };
    // 算法入口
    private static String getResult(String s) {
        Map<Character, Integer> letterCount = new HashMap<>();
        // 统计字母出现次数
        for (char c : s.toCharArray()) {
            letterCount.put(c, letterCount.getOrDefault(c, 0) + 1);
        }
        // 将 Map 转换为 List 以便排序
        List<Map.Entry<Character, Integer>> letterList = new ArrayList<>(letterCount.entrySet());
        letterList.sort(cmp);  // 使用自定义比较器进行排序
        // 生成输出字符串
        StringBuilder result = new StringBuilder();
        for (Map.Entry<Character, Integer> entry : letterList) {
            result.append(entry.getKey()).append(":").append(entry.getValue()).append(";");  // 构造输出格式
        }
        return result.toString();
    }
}
        题目内容
给出一个仅包含字母的字符串,不包含空格,统计字符串中各个字母(区分大小写)出现的次数,并按照字母出现次数从大到小的顺序。
输出各个字母及其出现次数。如果次数相同,按照自然顺序进行排序,且小写字母在大写字母之前。
输入描述
输入一行,为一个仅包含字母的字符串。
输出描述
按照字母出现次数从大到小的顺序输出各个字母和字母次数,用英文分号分隔,注意末尾的分号;
字母和次数间用英文冒号分隔。
样例1
输入
xyxyXX
输出
x:2;y:2;X:2;
说明
每个字符出现的个数都是2,故x排在y之前,而小写字母x在X之前
样例2
输入
abababb
输出
b:4;a:3;
说明
b的出现个数比a多,故b排在a之前