LEETCODE每日学习03.08

本文深入探讨了零钱兑换问题的算法解决方案,采用动态规划思想,结合Python的装饰器特性,实现了高效的问题求解。同时,介绍了Python装饰器的工作原理及在实际编程中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述 —— 零钱兑换:
给定不同面额的硬币 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() 函数。

实际上,所谓函数装饰器,就是通过装饰器函数,在不修改原函数的前提下,来对函数的功能进行合理的扩充。

***
  1. ->描述函数的返回类型,写法通常是
		def add(x, y) -> int:
  			return x+y

  1. functools模块是为了高阶函数设置的。这个高阶函数是作用于或返回其它函数的函数。一般来说,任何可调用的对象在该模块中都可被当做函数而处理。形如
    @functools. lru_cache(maxsize=128, typed=False)
    
    装饰器生成一个可调用的内存来保存最近调用,这个调用不超过maxsize指定的大小,并用其来装饰函数。当需要使用相同的参数周期性的调用I/O绑定函数或高消耗函数时,它可以保存时间。
    这么写的目的是为了避免重复的计算。我们将每个子问题的答案存在一个数组中进行记忆化,如果下次还要计算这个问题的值直接从数组中取出返回即可,这样能保证每个子问题最多只被计算一次。

简易答案:

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值