每日一题——Python实现PAT甲级1042 Shuffling Machine(举一反三+思想解读+逐步优化)


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

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

Python-3.12.0文档解读

目录

我的写法

功能分析

时间复杂度

空间复杂度

总结

代码点评

我要更强

优化方向

优化后的代码

优化分析

代码点评

哲学和编程思想

1. 空间-时间权衡(Space-Time Tradeoff)

2. 内存重用(Memory Reuse)

3. 最小化副作用(Minimize Side Effects)

4. 简洁性(Simplicity)

5. 局部性原理(Principle of Locality)

6. KISS 原则(Keep It Simple, Stupid)

7. DRY 原则(Don't Repeat Yourself)

举一反三

1. 空间-时间权衡(Space-Time Tradeoff)

技巧:

示例:

2. 内存重用(Memory Reuse)

技巧:

示例:

3. 最小化副作用(Minimize Side Effects)

技巧:

示例:

4. 简洁性(Simplicity)

技巧:

示例:

5. 局部性原理(Principle of Locality)

技巧:

示例:

6. KISS 原则(Keep It Simple, Stupid)

技巧:

示例:

7. DRY 原则(Don't Repeat Yourself)

技巧:

示例:

总结


 题目链接
 


我的写法

K = int(input())  # 读取输入的K值,表示需要进行洗牌的次数
orders = list(map(int, input().split()))  # 读取输入的顺序列表,表示洗牌后的顺序

# 初始化一副扑克牌
init_cards = []
init_cards += ['S' + str(i + 1) for i in range(13)]  # 添加黑桃(S)1到13
init_cards += ['H' + str(i + 1) for i in range(13)]  # 添加红桃(H)1到13
init_cards += ['C' + str(i + 1) for i in range(13)]  # 添加梅花(C)1到13
init_cards += ['D' + str(i + 1) for i in range(13)]  # 添加方块(D)1到13
init_cards.append('J1')  # 添加小王(J1)
init_cards.append('J2')  # 添加大王(J2)

outputs = []  # 初始化输出列表

for i in range(K):  # 进行K次洗牌
    outputs = [''] * 54  # 每次洗牌后创建一个空的输出列表
    for j in range(54):  # 遍历每一张牌
        outputs[orders[j] - 1] = init_cards[j]  # 根据orders中的顺序将init_cards中的牌放到对应位置
    init_cards = outputs  # 更新init_cards为新排列的牌,准备进行下一次洗牌

print(*outputs)  # 打印最终结果,将输出列表中的牌以空格分隔


 

这段代码是一个模拟扑克牌洗牌过程的程序,详细分析如下:

功能分析

这段代码的功能是根据用户输入的顺序 orders 和洗牌次数 K 模拟扑克牌的洗牌过程。输入顺序 orders 是一个包含 54 个整数的列表,表示每张牌在洗牌之后的新位置。程序按照这个顺序对扑克牌进行 K 次洗牌,并最终输出洗牌后的扑克牌顺序。

时间复杂度

  1. 初始化扑克牌:
    • 使用列表推导式初始化扑克牌,时间复杂度为 (O(1)),因为这是固定的 54 张牌。
  2. 洗牌过程:
  • 外层循环执行 (K) 次,其中 (K) 是输入的洗牌次数。
  • 内层循环执行 54 次,处理每一张牌的移动。
  • 整体的时间复杂度为 (O(K \times 54)),即 (O(54K))。通常情况下 (O(54K)) 可以简化为 (O(K)),因为 54 是一个常数。

空间复杂度

  1. 固定空间:
    • init_cards 和 outputs 各有 54 个元素,空间复杂度为 (O(54)),即 (O(1)),因为 54 是常数。
    • 其它变量如 K 和 orders(长度为 54)也是常量级别的空间开销。
  2. 洗牌过程:
  • 在每次洗牌中,新的 outputs 列表会覆盖旧的 init_cards 列表,但总的占用空间仍然是两个 54 元素的列表,空间复杂度为 (O(54 \times 2)),即 (O(108))。但这仍然是常数级别,简化为 (O(1))。

总结

  • 时间复杂度: (O(K))
  • 空间复杂度: (O(1))

代码点评

  1. 代码结构清晰:初始化扑克牌,循环 K 次洗牌,最后输出结果,逻辑非常清晰。
  2. 注释明确:每步操作都有详细注释,便于理解。
  3. 效率合理:时间复杂度和空间复杂度都很低,适用于大多数实际应用场景。
  4. 可扩展性:如果扑克牌数目或洗牌规则发生变化,代码也易于修改和扩展。

总体来说,这段代码简洁高效,符合专业编程规范。


我要更强

优化这段代码的时间复杂度和空间复杂度并不容易,因为洗牌过程本身需要对每张牌进行重新排列。然而,可以通过减少不必要的内存分配和复制来优化空间使用。以下是几个可能的优化方向:

优化方向

  1. 内存优化:避免在每次洗牌时创建新的列表,而是使用额外的空间来保存当前和下一步的状态。
  2. 减少复制操作:尽量减少对列表的整体复制操作。

优化后的代码

通过优化空间使用,我们可以改进代码的内存效率。以下是优化后的代码:

K = int(input())  # 读取输入的K值,表示需要进行洗牌的次数
orders = list(map(int, input().split()))  # 读取输入的顺序列表,表示洗牌后的顺序

# 初始化一副扑克牌
init_cards = []
init_cards += ['S' + str(i + 1) for i in range(13)]  # 添加黑桃(S)1到13
init_cards += ['H' + str(i + 1) for i in range(13)]  # 添加红桃(H)1到13
init_cards += ['C' + str(i + 1) for i in range(13)]  # 添加梅花(C)1到13
init_cards += ['D' + str(i + 1) for i in range(13)]  # 添加方块(D)1到13
init_cards.append('J1')  # 添加小王(J1)
init_cards.append('J2')  # 添加大王(J2)

current = init_cards[:]  # 当前牌组初始化为init_cards的复制
next_cards = [''] * 54  # 初始化一个空的牌组用于保存下一步结果

for i in range(K):  # 进行K次洗牌
    for j in range(54):  # 遍历每一张牌
        next_cards[orders[j] - 1] = current[j]  # 根据orders中的顺序将current中的牌放到对应位置
    current, next_cards = next_cards, current  # 交换current和next_cards,准备进行下一次洗牌

print(*current)  # 打印最终结果,将current牌组中的牌以空格分隔

优化分析

  1. 时间复杂度:
    • 外层循环执行 (K) 次,其中 (K) 是输入的洗牌次数。
    • 内层循环执行 54 次,处理每一张牌的移动。
    • 时间复杂度仍为 (O(K \times 54)),即 (O(K)),因为 54 是常数。
  2. 空间复杂度:
  • 使用了两个固定大小的列表 current 和 next_cards,每个列表包含 54 个元素。
  • 总的空间复杂度还是 (O(54 \times 2)),即 (O(1)),因为 54 是常数。

代码点评

  • 内存优化:新代码避免了重复分配和复制列表,通过交换引用来保存洗牌结果。
  • 逻辑清晰:洗牌过程的逻辑保持不变,代码结构仍然清晰易懂。
  • 效率提升:减少了内存分配和复制操作,提高了内存使用效率。

总的来说,这段优化后的代码在保留了原有逻辑的基础上优化了内存使用,更加高效。


哲学和编程思想

优化代码不仅仅是一个技术问题,也涉及到一些哲学和编程思想。这些思想可以帮助我们更好地理解为什么进行某些优化,以及如何进行有效的优化。以下是这段代码优化涉及到的主要哲学和编程思想:

1. 空间-时间权衡(Space-Time Tradeoff)

  • 哲学:在计算中,有时我们可以用更多的空间来换取更少的时间,反之亦然。这种权衡是许多优化决策的核心。
  • 应用:在这段代码中,通过使用两个固定大小的列表(current 和 next_cards),我们避免了每次洗牌都创建新的列表,从而节省了时间。

2. 内存重用(Memory Reuse)

  • 哲学:重用现有的资源而不是频繁分配和释放资源,可以提高效率和性能。
  • 应用:我们通过交换 current 和 next_cards 的引用来重用内存,而不是每次都创建新的列表。这减少了内存分配的开销,提高了性能。

3. 最小化副作用(Minimize Side Effects)

  • 哲学:减少函数或过程对外部状态的影响,有助于提高代码的可维护性和可预测性。
  • 应用:通过交换引用而不是复制列表,我们有效地将副作用限制在局部变量内部。这使得代码更容易理解和维护。

4. 简洁性(Simplicity)

  • 哲学:简洁的代码通常更容易理解、维护和调试。复杂性应尽可能地被消除。
  • 应用:代码结构清晰,逻辑明确,没有不必要的操作,保持了代码的简洁性。

5. 局部性原理(Principle of Locality)

  • 哲学:程序应尽量在局部范围内操作数据,以提高缓存效率和性能。
  • 应用:通过使用固定大小的列表,我们确保操作是局部的,数据在内存中的位置相对固定,从而提高了缓存命中率。

6. KISS 原则(Keep It Simple, Stupid)

  • 哲学:代码应保持尽可能简单,不引入不必要的复杂性。
  • 应用:通过简单地交换列表的引用,而不是复杂的复制和分配操作,我们遵循了 KISS 原则。

7. DRY 原则(Don't Repeat Yourself)

  • 哲学:尽量避免代码重复,提取公共逻辑到单一的地方。

应用:在优化过程中,避免了重复分配和复制列表的操作,集中在一个简单的引用交换上。


举一反三

理解并应用这些哲学和编程思想可以帮助你在编程中举一反三,开发出更高效、可维护的代码。以下是一些技巧和建议,结合之前提到的哲学和编程思想,帮助你在实际编程中应用:

1. 空间-时间权衡(Space-Time Tradeoff)

技巧:
  • 缓存计算结果:如果一个函数的计算结果会被多次使用,可以缓存结果以减少重复计算。
  • 预处理数据:在数据处理前进行一些预处理,可能会增加一些空间开销,但可以显著减少后续处理时间。
示例:

def fibonacci(n, memo={}):
    if n in memo:
        return memo[n]
    if n <= 1:
        return n
    memo[n] = fibonacci(n-1, memo) + fibonacci(n-2, memo)
    return memo[n]

2. 内存重用(Memory Reuse)

技巧:
  • 池化对象:复用对象而不是频繁地创建和销毁它们,比如使用对象池。
  • 就地修改:当安全和可行时,尽量就地修改数据而不是创建新的副本。
示例:

def in_place_reverse(arr):
    left, right = 0, len(arr) - 1
    while left < right:
        arr[left], arr[right] = arr[right], arr[left]
        left += 1
        right -= 1

3. 最小化副作用(Minimize Side Effects)

技巧:
  • 函数式编程:尽量编写纯函数(无副作用),避免修改全局状态。
  • 局部变量:使用局部变量而不是全局变量或类变量来保存临时状态。
示例:

def pure_function(x, y):
    return x + y

4. 简洁性(Simplicity)

技巧:
  • 拆分函数:将复杂的函数拆分成多个小函数,每个函数只做一件事。
  • 清晰命名:使用清晰、描述性的变量和函数名称,便于理解代码意图。
示例:

def process_data(data):
    clean_data = clean(data)
    transformed_data = transform(clean_data)
    return transformed_data

def clean(data):
    # 清理数据
    pass

def transform(data):
    # 转换数据
    pass

5. 局部性原理(Principle of Locality)

技巧:
  • 数据局部性:尽量让相关的数据在内存中存放在一起,减少缓存未命中。
  • 代码局部性:尽量在一个局部范围内完成相关操作,减少跨模块调用。
示例:

def sum_of_squares(arr):
    return sum(x * x for x in arr)

6. KISS 原则(Keep It Simple, Stupid)

技巧:
  • 避免过度优化:在没有明确性能问题时,不要过早进行复杂的优化。
  • 直观实现:优先选择直观、简单的实现方法,复杂的方法留作备选。
示例:

def calculate_area(radius):
    return 3.14 * radius * radius  # 简单计算圆的面积

7. DRY 原则(Don't Repeat Yourself)

技巧:
  • 抽取公共代码:将重复出现的代码抽取到一个独立函数或模块中。
  • 使用参数化:通过参数化来减少代码重复,增强代码的灵活性。
示例:

def calculate(operation, x, y):
    if operation == 'add':
        return x + y
    elif operation == 'subtract':
        return x - y
    # 更多操作...

总结

通过理解和应用这些哲学和编程思想,可以帮助在编程中实现以下目标:

  • 优化性能:通过合理的空间-时间权衡和内存重用,改进代码效率。
  • 提高可维护性:通过最小化副作用、保持代码简洁和避免重复,增强代码的可读性和可维护性。
  • 提高代码局部性:通过遵循局部性原理,改进代码运行效率和可预测性。

记住,这些技巧和思想不是独立的,而是相互关联和互补的。理解和实践这些思想不仅能提高你的编程能力,还能写出更加优雅和高效的代码。


感谢。

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

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

相关文章

数据库开发-Mysql03

目录 1. 多表查询 1.1 概述 1.1.1 数据准备 1.1.2 介绍 1.1.3 分类 1.2 内连接 1.3 外连接 1.4 子查询 1.4.1 介绍 1.4.2 标量子查询 1.4.3 列子查询 1.4.4 行子查询 1.4.5 表子查询 1.5 案例 2. 事务 2.1 介绍 2.2 操作 2.3 四大特性 3. 索引 3.1 介绍 3…

光伏企业供应链采购数字化转型升级路径

随着中国光伏行业引领全球&#xff0c;光伏行业竞争激烈。在供应链方面的处理能力也需要有更好的提升。本身光伏企业采购体系依赖传统采购方式&#xff0c;除了需要采购人员耗费大量的时间做供应商的背景调查之外&#xff0c;大量环节却依靠人工线下的方式完成&#xff0c;比如…

微服务 feign-gateway

早期微服务跨集群调用 使用的是Eureka 和RestTemplate&#xff0c;这种写法虽然可以解决服务之间的调用问题 ,但是随着服务的增多&#xff0c;实例变动&#xff0c;早期的写法相当于把请求方式&#xff0c;请求地址&#xff0c;参数写死了&#xff0c;耦合度太高&#xff0c;参…

OpenAI助手API接入-问答对自动生成

支持GPT-3.5-Turbo, GPT-4o, GPT-4-Turbo import json import openai from pathlib import Path import os client openai.OpenAI(base_urlbase_url, api_keyapi_key) file client.files.create( fileopen("H3.pdf", "rb"), purposeassistants ) …

Matplotlib | 绘制柱状图

简介 安装 Matplotlib 开始绘制 简单柱状图 改变颜色 改变纹理 改变边框样式 改变透明度 改变柱子宽度 改变图表标题 ​编辑 并列柱状图 横向柱状图 堆叠柱状图 更多函数 简介 柱状图&#xff08;Bar chart&#xff09;&#xff0c;是一种以长方形的长度为变量的…

重庆人文科技学院建立“软件安全产学研基地”,推动西南地区软件安全发展

5月29日&#xff0c;重庆人文科技学院与开源网安签订了《产学研校企合作协议》&#xff0c;并举行了“重庆人文科技学院产学研基地”授牌仪式&#xff0c;此次合作不仅深化了双方在软件安全领域的产学研紧密联结&#xff0c;更是对川渝乃至西南地区软件供应链安全发展起到重要的…

缓冲区溢出攻击

缓冲区溢出攻击 缓冲区溢出概述基础概念缓冲区溢出根源缓冲区溢出危害性&普遍性 缓冲区溢出攻击原理内存分配模式缓冲区溢出攻击缓冲区溢出攻击原理缓冲区溢出攻击分类堆栈溢出堆栈相关知识攻击原理 堆溢出攻击堆简介堆溢出DWORD SHOOT BSS段溢出 缓冲区溢出攻击防御措施防…

npm install pubsub-js报错的解决汇总

我在练习谷粒商城P83时&#xff0c;选择分类时触发向后端请求选择分类catId绑定的品牌数据&#xff0c;发现前端控制台报错&#xff1a; "PubSub is not definded",找不到pubsub。 因为缺少pubsub包&#xff0c;所以开始安装此包。 于是在网上一顿搜索猛如虎&…

使用Python库Matplotlib绘制常用图表类型

使用Python库Matplotlib绘图 一、Matplotlib绘图参数设置1.1 设置分辨率和画布大小1.2 保存图片并设置边缘留白为紧凑型1.3 设置坐标轴标签1.4 画直线设置线宽和颜色1.5 画子图1.5.1 通过figure的add_subplot()画子图1.5.2 通过plt的subplots画子图 二、使用Matplotlib中scatte…

Geek Uninstaller丨轻盈免费无需安装,Win超强卸载工具

以前卸载软件用习惯了uninstall tool&#xff0c;今天试了一下geek&#xff0c;对比一下还是geek卸载软件更轻盈一点&#xff0c;没有太多冗杂的步骤。 Geek Uninstaller 是一款轻量级的软件卸载工具&#xff0c;它可以帮助用户彻底删除电脑上的软件&#xff0c;包括那些顽固的…

【因果推断python】8_线性回归模型2

目录 回归理论 非随机数据的回归 回归理论 我不打算深入研究线性回归是如何构建和估计的。然而&#xff0c;一点点理论将有助于解释它在因果推断中的力量。首先&#xff0c;回归解决了理论上的最佳线性预测问题。令 是一个参数向量&#xff1a; 线性回归找到最小化均方误差 (…

JavaScript倍速播放视频

F12打开开发者工具&#xff0c;打开控制台&#xff0c;输入这行代码&#xff0c;视频即可加速播放&#xff0c; 可以调整倍速&#xff08;2&#xff0c;4&#xff0c;8&#xff0c;16&#xff09; document. getElementsByTagName("video")[0]. playbackRate16

单片机建立自己的库文件(1)

文章目录 前言一、代码模块化是什么&#xff1f;二、使用步骤1.以LCD1602作为例子2.将LCD1602 相关的代码抽取到另外一个文件中 三、调用LCD1602.h1.新建一个工程项目&#xff0c;将LCD1602.h添加到工程中2.在主函数上加入 #include <LCD1602.h> 总结 前言 提示&#xf…

MACOS安装 vue 抱错解决方法npm ERR! code EACCESnpm ERR! syscall mkdirnpm ERR!

问题 在使用脚手架 vue-cli 创建 vue 工程的时候存在权限不足的情况下&#xff0c;报错&#xff1b; npm error code EACCES npm error syscall open npm error path /Users/ npm ERR! code EACCESnpm ERR! syscall mkdirnpm ERR! 解决方案&#xff1a; sudo npm cache cl…

Go跨平台编译

1.编译windows平台运行程序 # windows env GOOSwindows GOARCHamd64 go build main.go2.编译linux平台运行程序 # linux env GOOSlinux GOARCHamd64 go build main.go 3.编译macos平台运行程序 # macos env GOOSdarwin GOARCHamd64 go build main.go 编译结果:

VQAScore开启文本到视觉生成评估新篇章

随着生成式人工智能技术的飞速发展&#xff0c;如何全面评估生成内容的质量和与输入提示的一致性成为了一个挑战。在图像-文本对齐领域&#xff0c;传统的评估方法如CLIPScore存在局限性&#xff0c;尤其是在处理涉及多个对象、属性和关系的复杂提示时。它们通常基于简单的词袋…

Linux域名解析不了/网络不可达/虚拟机连接不了的问题

记录域名解析不了/网络不可达/虚拟机连接不了的问题问题 目录 文章目录 记录域名解析不了/网络不可达/虚拟机连接不了的问题问题1.首先确定已经连接上路由器(我的就是在这嗝屁了....)1.1 查看路由表1.2查看当前的网络连接状态&#xff0c;包括网关1.3查看网络接口的状态&…

机器学习笔记 - PyTorch 分布式训练概览

一、简述 对于大规模的数据集,只能进行分布式训练,分布式训练会尽可能的利用我们的算力,使模型训练更加高效。PyTorch提供了Data Parallel包,它可以实现单机、多GPU并行。 PyTorch 数据并行模块的内部工作原理 上面的图像说明了PyTorch 如何在单个系统中利用多个 G…

jmeter多用户登录并退出教程

有时候为了模拟更真实的场景&#xff0c;在项目中需要多用户登录并退出操作&#xff0c;大致参考如下 多用户登录前面已经实现&#xff1a;参考博文 多用户登录并退出jmx文件&#xff1a;百度网盘 提取码&#xff1a;0000 一、多用户退出操作 添加一个setUp线程组&#xff0…

pcdn如何规避运营商查封线路

在使用PCDN&#xff08;Private Content Delivery Network&#xff09;时&#xff0c;为了规避运营商查封线路&#xff0c;可以采取以下措施&#xff1a; 基于成本和宽带的调度&#xff1a;从CDN厂商的角度出发&#xff0c;考虑在不同业务量的地区进行调度&#xff0c;以减少在…