【Py/Java/C++三种语言OD独家2024E卷真题】20天拿下华为OD笔试之【排序】2024E-字符统计及重排【欧弟算法】全网注释最详细分类最全的华为OD真题题解

可上 欧弟OJ系统 练习华子OD、大厂真题
绿色聊天软件戳 od1441了解算法冲刺训练(备注【CSDN】否则不通过)

相关推荐阅读

从2024年8月14号开始,OD机考全部配置为2024E卷
注意几个关键点:

  1. 大部分的题目仍为往期2023A+B+C以及2024D的旧题。注意万变不离其宗,把方法掌握,无论遇到什么题目都可以轻松应对。
  2. 支持多次提交题目,以最后一次提交为准。可以先做200的再做100的,然后可以反复提交。
  3. E卷仍然为单机位+屏幕监控的形式进行监考。
  4. 进入考试界面新加入了这样一段话并且用红字标出,可以看出华子对作弊代考等行为是0容忍的,请各位同学认真学习,不要妄图通过其他违规途径通过考试。
    在这里插入图片描述

题目描述与示例

题目描述

给出一个仅包含字母的字符串,不包含空格,统计字符串中各个字母(区分大小写)出现的次数,

并按照字母出现次数从大到小的顺序。输出各个字母及其出现次数。

如果次数相同,按照自然顺序进行排序,且小写字母在大写字母之前。

输入描述

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

输出描述

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

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

示例一

输入

xyxyXX

输出

x:2;y:2;X:2;

示例二

输入

abababb

输出

b:4;a:3;

解题思路

非常常规的排序题,直接使用lambda函数排序即可。

本题唯一的难点在于,但是如何对大小写字母分开进行排序,同时使得最终的小写字母排在大写字母前面。

我们可以直接使用哈希表计数器Counter()来统计每一个字符出现的个数,cnt = Counter(s)

另外还要将cnt转化为适合排序的二维列表ans = [(k, v) for k, v in cnt.items()]

在排序时,首先按照出现频率从大到小来排序,即第一个排序依据为 -item[1]

而当不同字符出现频率相等时,小写字母需要排在前面

已知大写字母"A"-"Z"的ASCII码值为65-90,小写字母"a"-"z"的ASCII码值为97-122

如果直接设置item[0]作为第二个排序依据的话,会使得同频率的大写字母排在前面,这样不符合题意。

因此我们需要设置第二个排序依据为 int(item[0] < "a"),表示

  • item[0]为小写字母时,int(item[0] < "a") = 0
  • item[0]为大写字母时,int(item[0] < "a") = 1

那么当同一个字符的频率相等时,其是小写和大写字母对应的第二个排序依据分别为01

这样就可以完成小写字母排在大写字母前面的任务。

此时再设置第三个排序依据 item[0],则可以将所有小写字母或大写字母进行顺序排序。

整体的排序代码为

ans.sort(key = lambda item: (-item[1], int(item[0] < "a"), item[0]))

代码

python

# 题目:【模拟】2024E-字符统计及重排
# 分值:100
# 作者:许老师-闭着眼睛学数理化
# 算法:模拟,排序
# 代码看不懂的地方,请直接在群上提问


from collections import Counter

# 输入原字符串
s = input()
# 使用cnt统计每一个字符出现次数
cnt = Counter(s)
# 将哈希表cnt转化为二维列表ans
ans = [(k, v) for k, v in cnt.items()]
# 首先按照出现频率从大到小来排序,即第一个排序依据为 -item[1]
# 当出现频率相等时,小写字母需要排在前面,
# 大写字母"A"-"Z"的ASCII码值为65-90,小写字母"a"-"z"的ASCII码值为97-122,
# 如果直接设置item[0]作为第二个排序依据的话会使得同频率的大写字母排在前面
# 我们需要设置第二个排序依据为 int(item[0] < "a"),表示
# 当item[0]为小写字母时,int(item[0] < "a") = 0
# 当item[0]为大写字母时,int(item[0] < "a") = 1
# 那么当频率相等时,小写和大写字母的第二个排序依据分别为0和1,小写字母会排在大写字母前面
# 此时再设置第三个排序依据 item[0],则可以将所有小写字母或大写字母进行排序
ans.sort(key = lambda item: (-item[1], int(item[0] < "a"), item[0]))
# 用分号";"作为合并符连接ans中的元素,注意最末尾还需要再加上一个";"
print(";".join(f"{k}:{v}" for k, v in ans) + ";")

java

import java.util.*;
import java.util.stream.Collectors;

public class CharacterStatistics {
    public static void main(String[] args) {
        // 输入原字符串
        Scanner scanner = new Scanner(System.in);
        String s = scanner.nextLine();

        // 使用cnt统计每一个字符出现次数
        Map<Character, Integer> cnt = new HashMap<>();
        for (char ch : s.toCharArray()) {
            cnt.put(ch, cnt.getOrDefault(ch, 0) + 1);
        }

        // 将哈希表cnt转化为二维列表ans
        List<Map.Entry<Character, Integer>> ans = new ArrayList<>(cnt.entrySet());

        // 首先按照出现频率从大到小来排序,即第一个排序依据为 -item.getValue()
        // 当出现频率相等时,小写字母需要排在前面,
        // 大写字母"A"-"Z"的ASCII码值为65-90,小写字母"a"-"z"的ASCII码值为97-122,
        // 如果直接设置item.getKey()作为第二个排序依据的话会使得同频率的大写字母排在前面
        // 我们需要设置第二个排序依据为 (item.getKey() < 'a'),表示
        // 当item.getKey()为小写字母时,(item.getKey() < 'a') = false(0)
        // 当item.getKey()为大写字母时,(item.getKey() < 'a') = true(1)
        // 那么当频率相等时,小写和大写字母的第二个排序依据分别为0和1,小写字母会排在大写字母前面
        // 此时再设置第三个排序依据 item.getKey(),则可以将所有小写字母或大写字母进行排序
        ans.sort((item1, item2) -> {
            int freqCompare = item2.getValue().compareTo(item1.getValue());
            if (freqCompare != 0) {
                return freqCompare;
            } else {
                int caseCompare = Boolean.compare(Character.isUpperCase(item1.getKey()), Character.isUpperCase(item2.getKey()));
                if (caseCompare != 0) {
                    return caseCompare;
                } else {
                    return item1.getKey().compareTo(item2.getKey());
                }
            }
        });

        // 用分号";"作为合并符连接ans中的元素,注意最末尾还需要再加上一个";"
        StringBuilder output = new StringBuilder();
        for (Map.Entry<Character, Integer> entry : ans) {
            output.append(entry.getKey()).append(":").append(entry.getValue()).append(";");
        }
        System.out.println(output.toString());
    }
}

cpp

#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    // 输入原字符串
    string s;
    getline(cin, s);

    // 使用cnt统计每一个字符出现次数
    unordered_map<char, int> cnt;
    for (char ch : s) {
        cnt[ch]++;
    }

    // 将哈希表cnt转化为二维列表ans
    vector<pair<char, int>> ans(cnt.begin(), cnt.end());

    // 首先按照出现频率从大到小来排序,即第一个排序依据为 -item.second
    // 当出现频率相等时,小写字母需要排在前面,
    // 大写字母"A"-"Z"的ASCII码值为65-90,小写字母"a"-"z"的ASCII码值为97-122,
    // 如果直接设置item.first作为第二个排序依据的话会使得同频率的大写字母排在前面
    // 我们需要设置第二个排序依据为 (item.first < 'a'),表示
    // 当item.first为小写字母时,(item.first < 'a') = false(0)
    // 当item.first为大写字母时,(item.first < 'a') = true(1)
    // 那么当频率相等时,小写和大写字母的第二个排序依据分别为0和1,小写字母会排在大写字母前面
    // 此时再设置第三个排序依据 item.first,则可以将所有小写字母或大写字母进行排序
    sort(ans.begin(), ans.end(), [](const pair<char, int>& item1, const pair<char, int>& item2) {
        if (item1.second != item2.second) {
            return item1.second > item2.second;
        } else {
            bool isUpper1 = isupper(item1.first);
            bool isUpper2 = isupper(item2.first);
            if (isUpper1 != isUpper2) {
                return isUpper2; // 小写字母在前
            } else {
                return item1.first < item2.first;
            }
        }
    });

    // 用分号";"作为合并符连接ans中的元素,注意最末尾还需要再加上一个";"
    string output;
    for (const auto& item : ans) {
        output += item.first;
        output += ":";
        output += to_string(item.second);
        output += ";";
    }
    cout << output << endl;

    return 0;
}

时空复杂度

时间复杂度:O(NlogN)

空间复杂度:O(1)


华为OD算法/大厂面试高频题算法练习冲刺训练

  • 华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务300+同学成功上岸!

  • 课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

  • 每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!

  • 60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁

  • 可上全网独家的欧弟OJ系统练习华子OD、大厂真题

  • 可查看链接 大厂真题汇总 & OD真题汇总(持续更新)

  • 绿色聊天软件戳 od1336了解更多

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闭着眼睛学算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值