题目描述 —— 零钱兑换:
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可凑 成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
要点记录:
1.
@是语法糖/装饰器,写在一个函数B前面。这个函数作为参数传给@后面的函数A
#funA 作为装饰器函数
def funA(fn):
print("C语言中文网")
fn() # 执行传入的fn参数
print("http://c.biancheng.net")
return "装饰器函数的返回值"
@funA
def funB():
print("学习 Python")
此时输出是
C语言中文网
学习 Python
http://c.biancheng.net
如果再添加
print(funB)
那么输出结果就是
装饰器函数的返回值
也就是说, 将 B 作为参数传给 A() 函数,同时将 A() 函数执行完成的返回值反馈回 B。被“@函数A”修饰的函数B不再是原来的函数B,而是被替换成一个新的东西(取决于装饰器的返回值),即如果装饰器函数A的返回值为普通变量,那么被修饰的函数名就变成了变量名;同样,如果装饰器返回的是一个函数的名称,怎么被修饰的函数名B依然表示一个函数。
如果被修饰的函数本身带有参数,比较简单的解决方法就是在函数装饰器中嵌套一个函数,该函数带有的参数个数和被装饰器修饰的函数相同。可以参考如下代码:
def funA(fn):
# 定义一个嵌套函数
def say(arc):
print("Python教程:",arc)
return say
@funA
def funB(arc):
print("funB():", a)
funB("http://c.biancheng.net/python")
其实,它与以下程序等价
def funA(fn):
# 定义一个嵌套函数
def say(arc):
print("Python教程:",arc)
return say
def funB(arc):
print("funB():", a)
funB = funA(funB)
funB("http://c.biancheng.net/python")
因而输出都是
Python教程: http://c.biancheng.net/python
通过 funB() 函数被装饰器 funA() 修饰,funB 就被赋值为 say。这意味着,虽然我们在程序显式调用的是 funB() 函数,但其实执行的是装饰器嵌套的 say() 函数。
实际上,所谓函数装饰器,就是通过装饰器函数,在不修改原函数的前提下,来对函数的功能进行合理的扩充。
***
- ->描述函数的返回类型,写法通常是
def add(x, y) -> int:
return x+y
- functools模块是为了高阶函数设置的。这个高阶函数是作用于或返回其它函数的函数。一般来说,任何可调用的对象在该模块中都可被当做函数而处理。形如
装饰器生成一个可调用的内存来保存最近调用,这个调用不超过maxsize指定的大小,并用其来装饰函数。当需要使用相同的参数周期性的调用I/O绑定函数或高消耗函数时,它可以保存时间。@functools. lru_cache(maxsize=128, typed=False)
这么写的目的是为了避免重复的计算。我们将每个子问题的答案存在一个数组中进行记忆化,如果下次还要计算这个问题的值直接从数组中取出返回即可,这样能保证每个子问题最多只被计算一次。
简易答案:
import functools
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
@functools.lru_cache(amount)
def dp(rem):
if rem < 0: return -1
if rem == 0: return 0
mini = int(1e9)
for coin in self.coins:
res = dp(rem - coin)
if res >= 0 and res < mini:
mini = res + 1
return mini if mini < int(1e9) else -1
self.coins = coins
if amount < 1: return 0
return dp(amount)
P.S.:对python的类不太熟,翻了翻资料:
- __private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用
题目描述 —— 兰顿蚂蚁
一只蚂蚁坐在由白色和黑色方格构成的无限网格上。开始时,网格全白,蚂蚁面向右侧。每行走一步,蚂蚁执行以下操作。
(1) 如果在白色方格上,则翻转方格的颜色,向右(顺时针)转 90 度,并向前移动一个单位。
(2) 如果在黑色方格上,则翻转方格的颜色,向左(逆时针方向)转 90 度,并向前移动一个单位。
编写程序来模拟蚂蚁执行的前 K 个动作,并返回最终的网格。
网格由数组表示,每个元素是一个字符串,代表网格中的一行,黑色方格由 ‘X’ 表示,白色方格由 ‘_’ 表示,蚂蚁所在的位置由 ‘L’, ‘U’, ‘R’, ‘D’ 表示,分别表示蚂蚁 左、上、右、下 的朝向。只需要返回能够包含蚂蚁走过的所有方格的最小矩形。
class Solution:
def printKMoves(self, K):
dirs = [(0, -1), (-1, 0), (0, 1), (1, 0)]
black = set()#无序不重复集
pos, curr_dir = (0, 0), 2
# 模拟 K 步骤
for i in range(K):
if pos in black:
curr_dir = (curr_dir - 1) % 4
black.remove(pos)
else:
curr_dir = (curr_dir + 1) % 4
black.add(pos)
pos = (pos[0] + dirs[curr_dir][0], pos[1] + dirs[curr_dir][1])
all_x = [x for x, _ in black] + [pos[0]]
all_y = [y for _, y in black] + [pos[1]]
min_x, max_x = min(all_x), max(all_x)
min_y, max_y = min(all_y), max(all_y)
# 初始化矩阵为全白
matrix = [["_" for _ in range(min_y, max_y + 1)] for _ in range(min_x, max_x + 1)]
# 填充黑色
for x, y in black:
matrix[x - min_x][y - min_y] = "X"
# 填充方向
matrix[pos[0] - min_x][pos[1] - min_y] = ["L", "U", "R", "D"][curr_dir]
for i in range(len(matrix)):
matrix[i] = "".join(matrix[i])
return matrix