每日一题——Python实现PAT乙级1042 字符统计(举一反三+思想解读+逐步优化)

news2025/1/14 2:27:59


一个认为一切根源都是“自己不够强”的INTJ

个人主页:用哲学编程-CSDN博客
专栏:每日一题——举一反三
Python编程学习
Python内置函数

Python-3.12.0文档解读

目录

我的写法

优点

缺点和改进建议

时间复杂度分析

空间复杂度分析

改进后的代码

我要更强

优化方法1:使用字典

优化方法2:减少字母转换次数

优化方法3:提前退出

完整代码和注释

时间复杂度

空间复杂度

优化方法4:提前判断最大计数

哲学和编程思想

1. 使用字典而不是固定大小的列表

哲学和编程思想

2. 减少字母转换次数

哲学和编程思想

3. 提前退出

哲学和编程思想

4. 空间优化

哲学和编程思想

总结

举一反三

1. 动态分配与灵活性

2. 优化和效率

3. 贪心策略与及时决策

4. 空间时间权衡

总结



题目链接

我的写法

chars = input()  # 从用户输入获取字符串
counts = []  # 初始化一个空列表用于存储每个字符的计数

for i in range(123):  # 预先为所有ASCII值从0到122初始化计数列表
    counts.append(0)  # 将每个位置的计数初始化为0

for char in chars:  # 遍历输入字符串中的每个字符
    if char.isalpha():  # 检查字符是否是字母(a-z 或 A-Z)
        counts[ord(char.lower())] += 1  # 将字母转换为小写并增加相应位置的计数

max_count = 0  # 初始化最大计数为0
output_char = 'a'  # 初始化输出字符为'a'

for i in range(97, 123):  # 遍历小写字母的ASCII值范围(97到122,即'a'到'z')
    if counts[i] > max_count:  # 如果当前字母的计数大于当前最大计数
        max_count = counts[i]  # 更新最大计数
        output_char = chr(i)  # 更新输出字符为当前字母

print(f"{output_char} {max_count}")  # 打印出现次数最多的字母及其计数

这段代码的功能是找到用户输入字符串中出现次数最多的字母(忽略大小写)及其出现次数。以下是对这段代码的详细点评以及其时间复杂度和空间复杂度的分析:

优点

  1. 功能明确:代码的目标是清晰的,即统计字符串中每个字母的出现次数,并找出出现次数最多的字母。
  2. 兼容性:代码处理了大小写字母的情况,将所有字母转换为小写进行统一计数。
  3. 直观易懂:代码逻辑相对简单,容易理解。

缺点和改进建议

  1. 冗余初始化:初始化 counts 列表时为所有ASCII值从0到122分配空间,但实际上只需要处理字母,即范围只需97到122(小写字母a到z)。可以优化空间利用率。
  2. 代码冗长:有些地方可以简化,例如 counts 列表的初始化和检查字符是否为字母的方式。
  3. 错误处理:代码没有处理用户输入为空的情况,可能会导致意外行为。

时间复杂度分析

  • 初始化 counts 列表:这是一个固定大小的列表初始化,时间复杂度为 O(1)。
  • 字符串遍历:遍历字符串中的每个字符,时间复杂度为 O(n),其中 n 是字符串的长度。
  • 查找最大值:在固定大小(26个字母)的范围内查找最大值,时间复杂度为 O(1)。

综上所述,总的时间复杂度为 O(n),其中 n 是输入字符串的长度。

空间复杂度分析

  • counts 列表:由于该列表固定大小为123,占用的空间是固定的,空间复杂度为 O(1)。
  • 其他变量:其余变量(如 max_count、output_char)占用常数空间。

综上所述,总的空间复杂度为 O(1)。

改进后的代码

chars = input()  # 从用户输入获取字符串
counts = [0] * 26  # 初始化一个长度为26的列表用于存储字母a-z的计数

for char in chars:  # 遍历输入字符串中的每个字符
    if char.isalpha():  # 检查字符是否是字母(a-z 或 A-Z)
        counts[ord(char.lower()) - 97] += 1  # 将字母转换为小写并增加相应位置的计数

max_count = 0  # 初始化最大计数为0
output_char = 'a'  # 初始化输出字符为'a'

for i in range(26):  # 遍历字母的计数
    if counts[i] > max_count:  # 如果当前字母的计数大于当前最大计数
        max_count = counts[i]  # 更新最大计数
        output_char = chr(i + 97)  # 更新输出字符为当前字母

print(f"{output_char} {max_count}")  # 打印出现次数最多的字母及其计数

以上改进后的代码更简洁,空间利用更加合理,同时保持了总体时间复杂度和空间复杂度不变。


我要更强

虽然原始代码已经在时间复杂度上达到了 O(n) 的最佳情况,并且空间复杂度也已经很低,但是我们可以通过一些方法在合理范围内进一步优化。以下是一些可能的优化方法:

优化方法1:使用字典

使用字典而不是固定大小的列表来计数,可以动态分配空间,只为实际出现的字母分配空间。

优化方法2:减少字母转换次数

将字符转换为小写的操作可以提前完成一次,避免在循环中多次调用 char.lower()。

优化方法3:提前退出

如果我们能在遍历过程中确定最大值,并且输入数据量巨大时,理论上可以通过提前退出来减少不必要的遍历,但这个场景较为特殊,以下代码没有实现该优化。

完整代码和注释

以下是使用上述的一些优化方法的代码:

chars = input()  # 从用户输入获取字符串
counts = {}  # 使用字典初始化一个空字典用于存储字母的计数

for char in chars:  # 遍历输入字符串中的每个字符
    if char.isalpha():  # 检查字符是否是字母(a-z 或 A-Z)
        char_lower = char.lower()  # 将字母转换为小写,仅转换一次
        if char_lower in counts:  # 如果字典中已有该字母
            counts[char_lower] += 1  # 增加相应字母的计数
        else:
            counts[char_lower] = 1  # 否则初始化该字母的计数为1

max_count = 0  # 初始化最大计数为0
output_char = 'a'  # 初始化输出字符为'a'

for char, count in counts.items():  # 遍历字典中的每个字母及其计数
    if count > max_count:  # 如果当前字母的计数大于当前最大计数
        max_count = count  # 更新最大计数
        output_char = char  # 更新输出字符为当前字母

print(f"{output_char} {max_count}")  # 打印出现次数最多的字母及其计数

时间复杂度

  • 初始化字典:O(1)
  • 遍历字符串:O(n),其中 n 是字符串的长度。
  • 查找最大值:最坏情况是 O(26),但因为字母表的大小是常数,可以认为是 O(1)。

总的时间复杂度仍然是 O(n)。

空间复杂度

  • 字典:在最坏情况下,字典会包含所有26个字母,因此空间复杂度是 O(1)。

总的空间复杂度是 O(1),但相比固定大小的列表,这种方法在处理非字母字符很多的情况下会稍微节省一些空间。

优化方法4:提前判断最大计数

如果输入字符串非常大并且字母频率分布很不均匀,可以在遍历过程中通过一些启发式的方法提前判断最大计数并退出循环,但这种优化是高度特定情况的,实际意义有限,因此不进一步展示。

这些方法在合理范围内优化了代码的时间和空间复杂度,使得代码更加高效和简洁。


哲学和编程思想

在编程中,许多优化方法和编程思想与哲学理念和原则密切相关。以下是上面提到的一些优化方法及其背后的哲学和编程思想:

1. 使用字典而不是固定大小的列表

哲学和编程思想
  • 动态分配:这体现了“需要多少用多少”的思想,避免了不必要的资源分配。哲学上,这类似于“最小需求原理”(Principle of Least Demand),即只在需要的时候才分配资源。
  • 灵活性:字典提供了更大的灵活性和可扩展性,可以适应不同输入的多样性。

2. 减少字母转换次数

哲学和编程思想
  • 优化和效率:通过提前将字符转换为小写一次,减少了多次调用char.lower()的开销。这体现了“避免重复劳动”的原则。哲学上,这类似于“效率优先”(Efficiency First)的原则,即通过减少冗余操作来提高效率。
  • 最小化重复计算:编程中的一个重要思想是“避免重复计算”(Avoid Repetition),即尽量减少或消除对同一数据或操作的重复计算。

3. 提前退出

哲学和编程思想
  • 贪心策略:如果在遍历过程中能确定最大值,可以提前退出循环。这类似于贪心算法中的策略,即在每一步都做出当前最优选择,期望最终结果也是最优的。
  • 快捷处理:哲学上,这类似于“及时行乐”(Carpe Diem)或者“及时决策”的思想,即在合适的时候做出快速决策。

4. 空间优化

哲学和编程思想
  • 空间时间权衡:通过使用字典而不是固定大小的列表,能在某些情况下节省空间。这体现了“空间时间权衡”(Space-Time Tradeoff)的思想,即在某些情况下可以通过增加时间开销来节省空间,或者反过来。
  • 资源节约:哲学上,这类似于“节约主义”(Economy of Resources)的思想,即尽可能节约资源,避免浪费。

总结

这些编程思想和哲学理念在编写高效、健壮的代码时至关重要。通过理解和应用这些原则,我们不仅能够写出性能更好的代码,还能在不同情况下做出更加明智的设计决策。


举一反三

要将哲学和编程思想应用到实际编程中,并能够举一反三,以下是一些具体的技巧和方法:

1. 动态分配与灵活性

技巧:尽量使用动态数据结构(如列表、字典、集合等)来处理数据,而不是固定大小的数组。

  • 例子:如果不知道输入数据的具体大小,可以使用动态列表或字典。
  • 应用:在处理用户输入、文件数据或网络数据时,使用动态数据结构来适应变化的输入大小。

2. 优化和效率

技巧:避免不必要的重复计算或操作。提前计算并缓存结果,或者通过算法优化来减少计算量。

  • 例子:使用字典来缓存已经计算过的结果(如斐波那契数列)。
  • 应用:在多次查找操作中,可以使用哈希表来加速查找速度;在递归算法中,使用记忆化(Memoization)来保存中间结果。

3. 贪心策略与及时决策

技巧:在遍历数据时,如果可以确定某个条件立即满足,则提前退出循环或递归。

  • 例子:在寻找某个特定值时,一旦找到立即返回,避免继续不必要的遍历。
  • 应用:在搜索算法中,如二分查找、深度优先搜索(DFS)中提前判断并返回结果。

4. 空间时间权衡

技巧:在设计算法时,考虑空间和时间的权衡,选择最合适的方案。

  • 例子:对于需要频繁访问的数据,可以用更多的空间来保存中间结果,减少计算时间。
  • 应用:在动态规划中,使用辅助数组来保存结果;在大数据处理中,使用分布式计算来平衡计算速度和内存使用。

总结

通过理解和应用这些哲学和编程思想,可以在不同场景中灵活运用,写出更加高效、健壮和灵活的代码。关键在于:

  1. 评估需求:根据实际需求选择最合适的数据结构和算法。
  2. 避免冗余:尽量避免不必要的重复计算和操作。
  3. 权衡利弊:在空间和时间之间找到最佳平衡点。
  4. 灵活应变:根据输入数据的特性,灵活使用动态数据结构和提前决策策略。

这些技巧和方法不仅适用于具体问题的解决,还能培养编程中的思维方式,帮助在面对新问题时能够举一反三,找到最佳解决方案。


感谢阅读。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1805062.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关键字、保留字、标识符

关键字 关键字是被 Java 赋予了特定含义的英文单词。 关键字的字母全部小写。 保留字 现有的 Java 版本尚未使用,但是以后版本可能会作为关键字使用。自己命名标识符时需要避免使用这些保留字。 保留字有:byValue, cast, future, generic, inner, op…

数据并非都是正态分布:三种常见的统计分布及其应用

你有没有过这样的经历?使用一款减肥app,通过它的图表来监控自己的体重变化,并预测何时能达到理想体重。这款app预测我需要八年时间才能恢复到大学时的体重,这种不切实际的预测是因为应用使用了简单的线性模型来进行体重预测。这个…

【吊打面试官系列-Mysql面试题】BLOB 和 TEXT 有什么区别 ?

大家好,我是锋哥。今天分享关于 【BLOB 和 TEXT 有什么区别?】面试题,希望对大家有帮助; BLOB 和 TEXT 有什么区别 ? BLOB 是一个二进制对象,可以容纳可变数量的数据。TEXT 是一个不区分大小写的 BLOB。 1…

Java 语言概述 -- Java 语言的介绍、现在、过去与将来

大家好,我是栗筝i,这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 001 篇文章,在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验,并希望进…

使用proteus仿真51单片机的流水灯实现

proteus介绍: proteus是一个十分便捷的用于电路仿真的软件,可以用于实现电路的设计、仿真、调试等。并且可以在对应的代码编辑区域,使用代码实现电路功能的仿真。 汇编语言介绍: 百度百科介绍如下: 汇编语言是培养…

Knife4j 生成 API 文档

文章目录 Knife4j 简介使用步骤Knife4j 常用注解的列表案例注意 Knife4j 简介 Knife4j 是一个增强的 Swagger 文档生成工具,提供了更加友好的界面和更多功能,使得 API 文档更加美观且易于使用。它是基于 Spring Boot 和 Swagger 进行封装的,…

【下篇】从 YOLOv1 到 YOLOv8 的 YOLO 物体检测模型历史

YOLO 型号之所以闻名遐迩,主要有两个原因:其速度和准确性令人印象深刻,而且能够快速、可靠地检测图像中的物体。上回我解释了YoloX, 今天从Yolov6开始。 YOLOv6:面向工业应用的单级物体检测框架 美团视觉人工智能事业部(Meituan Vision AI Department)于 2022 年 9 月在…

《精通ChatGPT:从入门到大师的Prompt指南》第4章:避免常见错误

第4章:避免常见错误 在使用ChatGPT进行Prompt编写时,常见的错误可能会大大影响生成内容的质量和准确性。本章将详细讨论这些错误,并提供如何避免它们的建议。 4.1 不明确的指令 在使用ChatGPT时,一个常见的问题是指令不够明确。…

Vue3中的常见组件通信之$attrs

Vue3中的常见组件通信之$attrs 概述 ​ 在vue3中常见的组件通信有props、mitt、v-model、 r e f s 、 refs、 refs、parent、provide、inject、pinia、slot等。不同的组件关系用不同的传递方式。常见的撘配形式如下表所示。 组件关系传递方式父传子1. props2. v-model3. $re…

LLVM Cpu0 新后端4

想好好熟悉一下llvm开发一个新后端都要干什么,于是参考了老师的系列文章: LLVM 后端实践笔记 代码在这里(还没来得及准备,先用网盘暂存一下): 链接: https://pan.baidu.com/s/1V_tZkt9uvxo5bnUufhMQ_Q?…

动态规划学习(分组背包)

分组背包的定义 分组背包是相比于01背包来讲,其就是多了一个组,给你n个组,每个组里有各自的物品,每个组里的物品只能选择一个,问你,选出来的最大价值是多少 这里我们的遍历顺序的三层循环,最外…

Burp Suite Professional 2024.5 (macOS, Linux, Windows) - Web 应用安全、测试和扫描

Burp Suite Professional 2024.5 (macOS, Linux, Windows) - Web 应用安全、测试和扫描 Burp Suite Professional, Test, find, and exploit vulnerabilities. 请访问原文链接:Burp Suite Professional 2024.5 (macOS, Linux, Windows) - Web 应用安全、测试和扫描…

Spring boot+vue前后端分离

目录 1、前端vue的搭建 2、后端项目的构建 pom文件中引入的jar包 yml文件用来配置连接数据库和端口的设置 application.property进行一些整合 service层 imp层 mapper 实体类 额外写一个类、解决跨域问题 3、测试 1、前端vue的搭建 建立项目的过程略 开启一个建立好…

Linux之进程信号详解【上】

🌎 Linux信号详解 文章目录: Linux信号详解 信号入门 技术应用角度的信号 信号及信号的产生       信号的概念       信号的处理方式 信号的产生方式         键盘产生信号         系统调用产生信号         软件…

python - pandas常用计算函数

文中所用数据集有需要的可以私聊我获取 学习目标 知道排序函数nlargest、nsmallest和sort_values的用法 知道Pandas中求和、计数、相关性值、最小、最大、平均数、标准偏差、分位数的函数使用 1 排序函数 导包并加载数据集 import pandas as pd ​ # 加载csv数据, 返回df对…

htb-linux-7-cronos-53-dns-nslookup-axfr

nmap DNS服务的枚举 靶机开启了53端口域名服务 枚举DNS服务 - nslookup 使用nslookup工具,设置DNS服务器的地址为10.10.10.13,需要查询10.10.10.13绑定的域名 枚举DNS服务 - axfr 使用dig工具来做区域传输(Zone Transfer)的查询:dig ax…

SpringBoot+Vue免税商品优选购物商城(前后端分离)

技术栈 JavaSpringBootMavenMySQLMyBatisVueShiroElement-UI 角色对应功能 用户商家 功能截图

记一次极其坑爹的 process.waitFor() 卡死问题

项目中有个需求需要截取wav的音频文件 ,网上找了找方法 用java调用ffmpeg 来截取 public static InputStream trimAudio(MultipartFile inputFile, Double startTime, Double endTime,Double volume) throws IOException {File file new File(FileUtil.getTmpDir…

程序猿大战Python——运算符

常见的运算符 目标:了解Python中常见的运算符有哪些? 运算符是用于执行程序代码的操作运算。常见的运算符有: (1)算术运算符:、-、*、/、//、% 、**; (2)赋值运算符&am…

“论边缘计算及应用”必过范文,突击2024软考高项论文

论文真题 边缘计算是在靠近物或数据源头的网络边缘侧,融合网络、计算、存储、应用核心能力的分布式开放平台(架构),就近提供边缘智能服务。边缘计算与云计算各有所长,云计算擅长全局性、非实时、长周期的大数据处理与分析,能够在…