力扣每日练习(3.20)补

322. 零钱兑换

想象你有一堆不同面值的硬币,现在的任务是用这些硬币凑出一个指定的金额,比如说11元,而且要求用的硬币数量尽可能少。

  1. 准备工作:首先,我们做了一张表(叫dp),这张表记录了从0元到目标金额(比如11元)每一个金额所需要的最少硬币数量。刚开始,我们假设每个金额所需的硬币数量都是最多的,这就像是一个最坏的情况。

  2. 开始计算:然后,我们开始尝试用手头上的每一种硬币去更新这张表。对于每一种硬币,我们看它能帮助减少哪些金额所需的硬币数量。

    • 比如,如果我们有1元和2元的硬币,我们就从1元和2元开始,一直尝试到11元,看看加入这种硬币后能不能让所需硬币数量更少。
    • 每次当我们考虑加入一个新的硬币时,我们会查看:如果我现在用这个硬币,再加上剩下的金额所需要的最少硬币数(这个信息已经在表里了),是不是比目前记录的要少。如果是,就更新这个金额所需的最少硬币数。
  3. 结果判断:最后,我们看看表中记录的目标金额所需的硬币数量是否被更新过(如果没有被更新过,说明用这些硬币凑不出这个金额),如果能凑出来,就告诉你需要的最少硬币数是多少。

python 复制代码
class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        # 初始化从0到目标金额的逐个列表
        dp = [amount+1 for _ in range(amount+1)]
        dp[0] = 0 # 金额0不要任何硬币

        # 遍历每个硬币
        for c in coins:
            # 遍历大于等于硬币面额的金额
            for i in range(c, amount+1):
                # 核心:更新当前金额的最少所需硬币数,求 只使用当前硬币的数量 和 使用一个当前硬币+差额所需的最小硬币数 的最小值
                dp[i] = min(dp[i], dp[i-c]+1)
        # 如果指定金额的硬币数没有被更新,说明没有组合能够满足
        return dp[-1] if dp[-1] != amount+1 else -1

dp[i] = min(dp[i], dp[i-c]+1) 这行代码是动态规划的核心。dp[i-c]+1表示如果你选择了面额为c的硬币,那么对于剩余的金额i-c,所需的最小硬币数就是dp[i-c],再加上你这次选择的这一枚硬币(也就是+1)。min(dp[i], dp[i-c]+1)的意思是,比较当前金额i所需最小硬币数的现有值(dp[i])和使用当前面额硬币新计算得到的值(dp[i-c]+1),取二者中的较小值作为新的最小硬币数。

78. 子集

以nums = [1, 2, 3]为例。想象一下,我们有一个空盒子(temp),我们可以决定是否要把一些数字放进去。我们的目标是找出所有可能的方式来填充这个盒子,也就是所有的子集。

开始时,我们的盒子是空的。这也是一个子集,所以我们先把它加到结果列表res中。现在,res = [[]]。

递归的魔法:我们用一个函数dfs来帮助我们决定每个数字是否放入盒子。

我们从第一个数字开始,看看我们可以把它放入盒子(即列表temp),然后我们继续看下一个数字。

每当我们考虑一个数字(比如1),我们会做两件事:一次尝试把它加入盒子,另一次则不加。对于每种情况,我们都会继续向下看下一个数字,直到没有更多数字为止。

添加子集:每次我们到达数字列表的末尾时,我们的盒子里装的就是一个完整的子集。我们把这个子集的一个复制(使用list(temp)来确保我们复制的是内容,而不是引用)加到结果res中。

回溯:这个词听起来有点复杂,但实际上很简单。就是当我们考虑完一个数字(比如1)放入盒子后,我们会把它拿出来(temp.pop()),就好像我们从未做过这个决定一样。这样我们就可以回到之前的状态,然后考虑不放入1的情况。这个过程让我们能够探索所有可能的组合。

结束:当我们考虑完所有的数字后,res就包含了所有可能的子集。

python 复制代码
class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        res = []
        def dfs(temp, index, nums):
            # 直接添加当前子集到结果列表中,无需等到最后
            res.append(list(temp))  # 使用list(temp)来复制当前子集
            
            # 遍历从当前索引到末尾的所有元素
            for i in range(index, len(nums)):
                # 包含当前元素
                temp.append(nums[i])
                # 递归调用处理下一个元素
                dfs(temp, i + 1, nums)
                # 回溯:移除当前元素,尝试下一个选择
                temp.pop()

        # 开始递归
        dfs([], 0, nums)

        return(res)

221. 最大正方形

定义状态 :我们可以定义一个二维的DP数组dp,其中dp[i][j]代表以(i, j)为右下角的最大正方形的边长。注意,这个定义是关键的,因为它让我们能够通过左边、上边和左上角的状态来决定当前位置的状态。
找到状态转移方程 :对于每个位置(i, j),如果该位置的值是'1',那么dp[i][j]应该是其左边、上边和左上角的dp值中的最小值加1。这是因为,一个位置如果要构成一个更大的正方形,它的左边、上边和左上角也必须能构成正方形。数学表达式为:dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1。
初始化 :对于矩阵的第一行和第一列,dp[i][j]就直接是矩阵中的值(因为它们只能形成最大边长为1的正方形)。
遍历矩阵填充DP数组 :从(1, 1)开始遍历整个矩阵,并根据状态转移方程更新DP数组。
找到最大的dp[i][j]:遍历DP数组,找到最大的值,这个值的平方即为最大正方形的面积。

创建了一个辅助矩阵,元素是int,这样就解决了对原始矩阵元素转换类型的问题,同时还有在原始矩阵里修改元素影响实际计算的问题。然后针对元素为'1'时才开始计算,同时考虑边界情况。状态转移方程是根据每一步前面的上、左、左上角的累计最小值+1决定当前1的边长,这样在本身自己是一个单位的基础上和上面的合起来就是2,依次累加

python 复制代码
class Solution:
    def maximalSquare(self, matrix: List[List[str]]) -> int:
        # 长宽,初始化最大边长
        rows,cols = len(matrix), len(matrix[0])
        max_side = 0

        # 辅助矩阵,全0初始化
        dp = [[0]*cols for _ in range(rows)] 

        # 遍历每个元素
        for r in range(rows):
            for c in range(cols):
                if matrix[r][c] != '0': # 为1才进行计算
                    if r == 0 or c == 0: # 对于边界情况进行处理
                        dp[r][c] = 1
                    else: # 状态转移方程,假设当前是正方形的右下角,其值由左、上、左上的最小值决定
                        dp[r][c] = min(dp[r][c-1], dp[r-1][c], dp[r-1][c-1]) + 1
                    # 更新最大边长
                    max_side = max(max_side, dp[r][c])
        # 边长2次方
        return max_side ** 2
相关推荐
C7211BA18 分钟前
使用knn算法对iris数据集进行分类
算法·分类·数据挖掘
Tisfy20 分钟前
LeetCode 2398.预算内的最多机器人数目:滑动窗口+单调队列——思路清晰的一篇题解
算法·leetcode·机器人·题解·滑动窗口
.普通人22 分钟前
c语言--力扣简单题目(回文链表)讲解
c语言·leetcode·链表
程序猿练习生24 分钟前
C++速通LeetCode简单第18题-杨辉三角(全网唯一递归法)
c++·算法·leetcode
Huazzi.27 分钟前
算法题解:斐波那契数列(C语言)
c语言·开发语言·算法
汉字萌萌哒28 分钟前
【2022 CCF 非专业级别软件能力认证第一轮(CSP-J1)入门级 C++语言试题及解析】
数据结构·c++·算法
2301_8071805429 分钟前
icpc江西:L. campus(dij最短路)
算法
th新港30 分钟前
CCF201909_1
数据结构·c++·算法·ccf
DdddJMs__13531 分钟前
C语言 | Leetcode C语言题解之题409题最长回文串
c语言·leetcode·题解
Dola_Pan31 分钟前
字符串的KMP算法详解及C/C++代码实现
算法