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

本文主要是介绍每日一题——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 nmemo[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) - 1while left < right:arr[left], arr[right] = arr[right], arr[left]left += 1right -= 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_datadef clean(data):# 清理数据passdef 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 + yelif operation == 'subtract':return x - y# 更多操作...

总结

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

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

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


感谢。

这篇关于每日一题——Python实现PAT甲级1042 Shuffling Machine(举一反三+思想解读+逐步优化)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1021195

相关文章

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

基于Python实现高效PPT转图片工具

《基于Python实现高效PPT转图片工具》在日常工作中,PPT是我们常用的演示工具,但有时候我们需要将PPT的内容提取为图片格式以便于展示或保存,所以本文将用Python实现PPT转PNG工具,希望... 目录1. 概述2. 功能使用2.1 安装依赖2.2 使用步骤2.3 代码实现2.4 GUI界面3.效

MySQL更新某个字段拼接固定字符串的实现

《MySQL更新某个字段拼接固定字符串的实现》在MySQL中,我们经常需要对数据库中的某个字段进行更新操作,本文就来介绍一下MySQL更新某个字段拼接固定字符串的实现,感兴趣的可以了解一下... 目录1. 查看字段当前值2. 更新字段拼接固定字符串3. 验证更新结果mysql更新某个字段拼接固定字符串 -

Python获取C++中返回的char*字段的两种思路

《Python获取C++中返回的char*字段的两种思路》有时候需要获取C++函数中返回来的不定长的char*字符串,本文小编为大家找到了两种解决问题的思路,感兴趣的小伙伴可以跟随小编一起学习一下... 有时候需要获取C++函数中返回来的不定长的char*字符串,目前我找到两种解决问题的思路,具体实现如下:

java实现延迟/超时/定时问题

《java实现延迟/超时/定时问题》:本文主要介绍java实现延迟/超时/定时问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java实现延迟/超时/定时java 每间隔5秒执行一次,一共执行5次然后结束scheduleAtFixedRate 和 schedu

Java Optional避免空指针异常的实现

《JavaOptional避免空指针异常的实现》空指针异常一直是困扰开发者的常见问题之一,本文主要介绍了JavaOptional避免空指针异常的实现,帮助开发者编写更健壮、可读性更高的代码,减少因... 目录一、Optional 概述二、Optional 的创建三、Optional 的常用方法四、Optio

python连接本地SQL server详细图文教程

《python连接本地SQLserver详细图文教程》在数据分析领域,经常需要从数据库中获取数据进行分析和处理,下面:本文主要介绍python连接本地SQLserver的相关资料,文中通过代码... 目录一.设置本地账号1.新建用户2.开启双重验证3,开启TCP/IP本地服务二js.python连接实例1.

在Android平台上实现消息推送功能

《在Android平台上实现消息推送功能》随着移动互联网应用的飞速发展,消息推送已成为移动应用中不可或缺的功能,在Android平台上,实现消息推送涉及到服务端的消息发送、客户端的消息接收、通知渠道(... 目录一、项目概述二、相关知识介绍2.1 消息推送的基本原理2.2 Firebase Cloud Me

Spring Boot项目中结合MyBatis实现MySQL的自动主从切换功能

《SpringBoot项目中结合MyBatis实现MySQL的自动主从切换功能》:本文主要介绍SpringBoot项目中结合MyBatis实现MySQL的自动主从切换功能,本文分步骤给大家介绍的... 目录原理解析1. mysql主从复制(Master-Slave Replication)2. 读写分离3.

Redis实现延迟任务的三种方法详解

《Redis实现延迟任务的三种方法详解》延迟任务(DelayedTask)是指在未来的某个时间点,执行相应的任务,本文为大家整理了三种常见的实现方法,感兴趣的小伙伴可以参考一下... 目录1.前言2.Redis如何实现延迟任务3.代码实现3.1. 过期键通知事件实现3.2. 使用ZSet实现延迟任务3.3