diff --git "a/279\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260.png" "b/279\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260.png" deleted file mode 100644 index 6b01e2bd2a3cfc1ce474efe5357685ded31d93bd..0000000000000000000000000000000000000000 Binary files "a/279\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260.png" and /dev/null differ diff --git a/alg.md b/alg.md index 036f97a5e096b82d513ddfb0b3009edb3a5e80b3..182f5f0cec5280388431ec0d87f25fbc237eb692 100644 --- a/alg.md +++ b/alg.md @@ -1,90 +1,78 @@ -# 解题报告:完全平方数 +# 三角形最小路径 -## 题目描述 +## 生成数据的思路 -给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。 + rand()产生随机种子,以此产生随机数。将num[][]初始化为0,再将数组各元素替换成生成的随机数。 -完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。 +```python +int num[5][5] = { 0 }; + while (num[4][4] == 0) + { + srand((int)time(0)); + for (int i = 0; i < 5; i++) + for (int j = 0; j <5; j++) + + { + int a = (rand() % 100) + 1; + num[i][j] = a; + } + } + cout << "生成随机三角形:" << endl; + for (int i = 0; i < 5; i++) + { + for (int j = 0; j < 5; j++) + if (i >= j) + cout << num[i][j] << ' '; + cout << endl; + } +``` - -## 思路分析 -该算法使用动态规划的思想,具体思路如下dp[i]的值为和为 i 的完全平方数的最少数量,我们从1开始一直算到n,每次dp[i]等于所有能再加一个完全平方数等于i的值中的最小值,dp中最后一个元素就是我们要寻找的和为 n 的完全平方数的最少数量。 +## 思路 -1. 定义状态:dp[i]表示数字i最少可以由几个完全平方数的和组成。 -2. 初始化状态:dp[0] = 0,其余dp[i]均为正无穷。 -3. 状态转移方程:对于数字i,遍历每个小于等于i的完全平方数j*j,将dp[i-j*j]+1与dp[i]取最小值。 -4. 返回结果:dp[n]为数字n最少可以由几个完全平方数的和组成。 +- 我们用 f[i][j] 表示从三角形顶部走到位置 (i,j) 的最小路径和。这里的位置 (i,j) 指的是三角形中第 i 行第 j 列(均从 0 开始编号)的位置。 -## 数据测试 + 由于每一步只能移动到下一行「相邻的节点」上,因此要想走到位置 (i,j),上一步就只能在位置 (i−1,j−1) 或者位置 (i−1,j)。我们在这两个位置中选择一个路径和较小的来进行转移,状态转移方程为:f[i][j]=min(f[i−1][j−1],f[i−1][j])+c[i][j] -为了测试算法的鲁棒性,我们需要生成一些随机的数据进行测试。生成数据的思路如下: + 其中 c[i][j] 表示位置 (i,j) 对应的元素值。 -1. 生成一个随机数n,表示数字n需要分解为完全平方数的和。 -2. 为了保证算法的正确性,n的范围应该从1到较大的数,例如1000。 -3. 返回一个包含n的元组,作为算法的输入数据。 + 注意第 i 行有 i+1 个元素,它们对应的 j 的范围为 j=i 时,上述状态转移方程中有一些项是没有意义的。例如当 j=0 时,f[i−1][j−1] 没有意义,因此状态转移方程为:f[i][0]=f[i−1][0]+c[i][0] -## 时间复杂度分析 + 即当我们在第 i 行的最左侧时,我们只能从第 i−1 行的最左侧移动过来。当 j=i 时,f[i−1][j] 没有意义,因此状态转移方程为:f[i][i]=f[i−1][i−1]+c[i][i] -O(n*sqrt(n))。外层循环遍历n个数字,内层循环遍历每个数字的平方根,因此总的时间复杂度为O(n*sqrt(n))。 + 即当我们在第 i 行的最右侧时,我们只能从第 i−1 行的最右侧移动过来。 -空间复杂度:O(n)。需要使用一个长度为n+1的数组来存储状态。 + 最终的答案即为 f[n−1][n−1] 中的最小值,其中 n 是三角形的行数。 -## 代码实现 ```python -from random import randint -def generate_data(): - n = randint(1, 1000) - return (n,) -from typing import List -class Solution: - def numSquares(self, n: int) -> int: - # 初始化dp数组 - dp = [float("inf")] * (n + 1) - dp[0] = 0 - # 遍历每个数 - for i in range(1, n + 1): - # 遍历每个完全平方数 - for j in range(1, int(i ** 0.5) + 1): - dp[i] = min(dp[i], dp[i - j*j] + 1) - return dp[n] -def generate_data(): - n = randint(1, 1000) - return (n,) - -``` +def minimumTotal(self, triangle: List[List[int]]) -> int: + n = len(triangle) + f = [[0] * n for _ in range(n)] + f[0][0] = triangle[0][0] -## 测试示例 + for i in range(1, n): + f[i][0] = f[i - 1][0] + triangle[i][0] + for j in range(1, i): + f[i][j] = min(f[i - 1][j - 1], f[i - 1][j]) + triangle[i][j] + f[i][i] = f[i - 1][i - 1] + triangle[i][i] + + return min(f[n - 1]) -​ 下面是一个测试代码的例子: -```python -def test(): - s = Solution() - for i in range(10): - n = i * 100 - res = s.numSquares(n) - print(f"For n = {n}, the minimum number of perfect squares is {res}") -if __name__ == "__main__": - test() ``` +**复杂度分析** +时间复杂度:O(n^2) +其中 n 是三角形的行数。 -![](C:\Users\XUZIY\Desktop\279完全平方数.png) - -## 心得体会 - -git用起来没有第一次那么坎坷,基本的操作都没有问题,也在不断地用一些新东西。这次实验,我在不断加深对动态规划问题的理解。 - -## 实验环境 +空间复杂度:O(n^2) +我们需要一个 n∗n 的二维数组存放所有的状态。 -win10 -python3.11 -jupyter notebook +## 测试结果 -git. \ No newline at end of file +![屏幕截图 2023-04-25 211755](C:\Users\崔\Pictures\Screenshots\屏幕截图 2023-04-25 211755.png) \ No newline at end of file diff --git a/alg.py b/alg.py index af2aed327f505ca8ff06164d68cd3843b00706bf..e3b6f8f17d1922662bf61df23c5c4f014b3c3a37 100644 --- a/alg.py +++ b/alg.py @@ -1,12 +1,13 @@ -from typing import List class Solution: - def numSquares(self, n: int) -> int: - # 初始化dp数组 - dp = [float("inf")] * (n + 1) - dp[0] = 0 - # 遍历每个数 - for i in range(1, n + 1): - # 遍历每个完全平方数 - for j in range(1, int(i ** 0.5) + 1): - dp[i] = min(dp[i], dp[i - j*j] + 1) - return dp[n] \ No newline at end of file + def minimumTotal(self, triangle: List[List[int]]) -> int: + n = len(triangle) + f = [[0] * n for _ in range(n)] + f[0][0] = triangle[0][0] + + for i in range(1, n): + f[i][0] = f[i - 1][0] + triangle[i][0] + for j in range(1, i): + f[i][j] = min(f[i - 1][j - 1], f[i - 1][j]) + triangle[i][j] + f[i][i] = f[i - 1][i - 1] + triangle[i][i] + + return min(f[n - 1]) \ No newline at end of file diff --git a/gen.py b/gen.py index 1c16f48d7f6b44ce2ec650a8a22ff7dadd368a72..c4bca9f99ff1eeabba57c1165a6254f2c0cff992 100644 --- a/gen.py +++ b/gen.py @@ -1,4 +1,20 @@ -nums = [3,2,1,6,0,5] - - +int num[5][5] = { 0 }; + while (num[4][4] == 0) + { + srand((int)time(0)); + for (int i = 0; i < 5; i++) + for (int j = 0; j <5; j++) + { + int a = (rand() % 100) + 1; + num[i][j] = a; + } + } + cout << "生成随机数组:" << endl; + for (int i = 0; i < 5; i++) + { + for (int j = 0; j < 5; j++) + if (i >= j) + cout << num[i][j] << ' '; + cout << endl; + } \ No newline at end of file diff --git a/test.py b/test.py index 3af305458bceaa91bf31e34600e040086adbadbe..70a76db77fb7fe924cbbf94ea9b974e008e72a0b 100644 --- a/test.py +++ b/test.py @@ -1,19 +1,6 @@ -import gen -import alg - -n = gen.nums -root = alg.constructMaximumBinaryTree(n) -# 前序遍历二叉树 -def preorderTraversal(root): - res = [] - def helper(root): - # 如果树为空,则返回None - if not root: - return None - res.append(root.val) - helper(root.left) - helper(root.right) - helper(root) - return res -# 输出遍历结果 -print(preorderTraversal(root)) +输入 +[[2],[3,4],[6,5,7],[4,1,8,3]] +输出 +11 +预期结果 +11 \ No newline at end of file