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


一个认为一切根源都是“自己不够强”的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. 灵活应变:根据输入数据的特性,灵活使用动态数据结构和提前决策策略。

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


感谢阅读。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Androi】安卓发展历程详解

人不走空 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌赋:斯是陋室,惟吾德馨 目录 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌…

轻NAS玩客云使用Docker部署小雅并挂载到AList详细流程分享

文章目录 前言1. 本地部署AList2. AList挂载网盘3. 部署小雅alist3.1 Token获取3.2 部署小雅3.3 挂载小雅alist到AList中 4. Cpolar内网穿透安装5. 创建公网地址6. 配置固定公网地址 前言 本文主要介绍如何在安装了CasaOS的玩客云主机中部署小雅AList,并在AList中挂…

YOLOv8_obb的训练、验证、预测及导出[旋转目标检测实践篇]

1.旋转目标检测数据集划分和配置 从上面得到的images和labels数据还不能够直接训练,需要按照一定的比例划分训练集和验证集,并按照下面的结构来存放数据,划分代码如下所示,该部分内容和YOLOv8的训练、验证、预测及导出[目标检测实践篇]_yolov8训练测试验证-CSDN博客是重复的…

LNMP与动静态网站介绍

Nginx发展 Nginx nginx http server Nginx是俄罗斯人 Igor Sysoev(伊戈尔.塞索耶夫)开发的一款高性能的HTTP和反向代理服务器。 Nginx以高效的epoll.kqueue,eventport作为网络IO模型,在高并发场景下,Nginx能够轻松支持5w并发连接数的响应,并…

Redis单线程运行与CPU多核心的关系

Redis单线程运行与CPU多核心的关系 Redis作为一种高性能的内存数据库,以其单线程的运行模式而闻名。在高并发的场景下,单线程模型有助于简化开发和避免竞争条件。然而,随着多核CPU的普及,人们不禁要问,Redis的单线程模…

FJSP:烟花算法(FWA)求解柔性作业车间调度问题(FJSP),提供MATLAB代码

一、烟花算法介绍 参考文献: Tan, Y. and Y. Zhu. Fireworks Algorithm for Optimization. in Advances in Swarm Intelligence. 2010. Berlin, Heidelberg: Springer Berlin Heidelberg. 二、烟花算法求解FJSP 2.1FJSP模型介绍 柔性作业车间调度问题(Flexible …

医疗器械网络安全风险管理的基本步骤

医疗器械网络安全风险管理是一个复杂的过程,涉及到多个环节和步骤。以下是一些基本的步骤和关键点: 风险识别:首先需要对医疗器械的软件、网络连接和通信协议等进行漏洞分析,识别潜在的安全漏洞和弱点。这可能涉及对设备的渗透测…

LLVM Cpu0 新后端7 第一部分 DAG调试 dot文件 Machine Pass

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

Nagios的安装和使用

*实验* *nagios安装和使用* Nagios 是一个监视系统运行状态和网络信息的监视系统。Nagios 能监视所指定的本地或远程主机以及服务,同时提供异常通知功能等. Nagios 可运行在 Linux/Unix 平台之上,同时提供一个可选的基于浏览器的 WEB 界面以方便系统管…

【Linux系统编程】进程地址空间

目录 前言 进程虚拟地址空间的引入 进程地址空间的概念 进一步理解进程地址空间 为什么需要进程地址空间? 系统层面理解malloc/new内存申请 前言 首先,在我们学习C语言的时候一定会见过如下这张图。(没见过也没关系,接下来…

stm32最小系统焊接调试总结

stm32最小系统打板后,接下来开始焊接元器件,焊接元器件可以参考立创EDA焊接辅助工具。 图1 焊接辅助助手 焊接准备工具有,焊台,放大镜,元器件,镊子,焊锡膏,锡丝及万用表等。调节焊台温度到350-400摄氏度。焊接顺序是先焊接USB typec接口,5V电源,ldo,ch340,stm32芯片…

【Python】一文向您详细介绍 __str__ 的作用和用法

【Python】一文向您详细介绍 str 的作用和用法 下滑即可查看博客内容 🌈 欢迎莅临我的个人主页 👈这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地!🎇 🎓 博主简介:985高校的普通本硕&…

Linux -- 正则表达式基础

提示:制作不易,可以点个关注和收藏哦。 前言 虽然我们这一节的标题是正则表达式,但实际这一节实验只是介绍grep,sed,awk这三个命令,而正则表达式作为这三个命令的一种使用方式(命令输出中可以包…

一个简单的threejs盒剖切功能

支持六面方向拖拽、反向、切面填充. 代码: import * as THREE from three import { MouseHandler } from src/renderers/input/mouse import {mergeGeometries} from three/examples/jsm/utils/BufferGeometryUtils import {BaseHandle} from ./base import {HANDL…

MathType7永久破解免费版下载最新2024

“数学公式”作为学术和科普写作中不可或缺的一环,一直困扰着很多作者。 在Word等文本编辑器中,虽然提供了插入公式的功能,但使用起来却并不友好,不仅效率低下,而且在调整格式时也会遇到各种问题。而MathType公式编辑器…

【Python机器学习】PCA——特征提取(2)

上一篇写过了用单一最近邻分类器训练后的精度只有0.22. 现在用PCA。想要度量人脸的相似度,计算原始像素空间中的距离是一种相当糟糕的方法。用像素表示来比较两张图像时,我们比较的是每个像素的灰度值与另一张图像对应位置的像素灰度值。这种表示与人们…

flask实现抽奖程序(一)

后端代码E:\LearningProject\lottery\app.py from flask import Flask, render_template import randomapp Flask(__name__)employees [赵一, 钱二, 孙三, 李四, 周五, 吴六, 郑七, 王八]app.route(/) def hello_world():return render_template(index.html, employeesemplo…

Centos7系统禁用Nouveau内核驱动程序【笔记】

在CentOS系统中,Nouveau是开源的NVIDIA显卡驱动程序,但它与NVIDIA的官方驱动程序NVIDIA Proprietary Driver存在兼容性问题。 如果你想要禁用Nouveau并使用NVIDIA官方驱动,可以按照以下步骤操作: 1、创建一个黑名单文件以禁用Nouveau驱动。 echo blacklist nouveau | su…

M3ID和CD的区别

M3ID的公式: CD的公式(概率空间版本): CD的公式(logits空间版本): 为简单对比,主要比较概率空间版本。logits空间版本已有证明和概率空间版本等效,在此不做详细讨论&a…

Transformer论文精读

Transformer:Attention is all you need Abstract: 在主流的序列转录模型(sequence transduction models:给一个序列,生成另一个序列),主要依赖循环或者卷积神经网络,一般是用enco…