一、动态规划法概述
动态规划法是一种解决多阶段决策过程最优化问题的数学方法。
二、基本思想
- 动态规划的基本思想是把原问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。它保存子问题的解,避免重复计算,从而提高算法效率。
- 具体而言,动态规划通常会寻找问题的最优子结构性质和子问题重叠性质。最优子结构性质是指问题的最优解可以由子问题的最优解组合而成;子问题重叠性质是指在求解过程中,不同的子问题会被重复求解多次。
三、求解过程
划分阶段:按照问题的时间顺序或空间特征,将问题划分为若干个阶段。
确定状态:定义每个阶段的状态,状态应能够描述该阶段的决策结果和问题的特征。
确定决策:明确在每个阶段可以采取的决策,决策会导致状态的转移。
写出状态转移方程:根据问题的逻辑关系,写出状态转移方程,即从一个状态转移到另一个状态的规则。
确定初始状态和边界条件:明确问题的初始状态和边界条件,以便从初始状态开始逐步求解。
求解问题:通常采用自底向上或自顶向下的方法,根据状态转移方程逐步求解每个状态的值,最终得到问题的最优解。
四、适用场合
资源分配问题:如在有限的资源下如何分配任务,使得总收益最大。
路径规划问题:寻找图中两点之间的最短路径。
背包问题:在给定容量的背包中,如何选择物品使得总价值最大。
生产调度问题:安排生产任务,以最小化生产时间或成本。
五、杨辉三角问题描述
给定一个非负整数
numRows,生成「杨辉三角」的前numRows行。(在「杨辉三角」中,每个数是它左上方和右上方的数的和)
题解示例
示例 1:
输入: numRows = 5
输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
示例 2:
输入: numRows = 1
输出: [[1]]
六、用动态规划法解决杨辉三角问题的思路
定义状态:我们可以将杨辉三角的每一行看作一个状态。用
resultList.get(i)表示杨辉三角中第i行的状态,其中每一行又是一个由整数组成的列表,列表中的每个元素对应杨辉三角该行中的某一列数字。确定状态转移方程:对于杨辉三角,状态转移方程体现为代码中的
rowNow.add(rowLast.get(j - 1) + rowLast.get(j)),即当j > 0 && j < i时,当前行(用rowNow表示)第j个位置的数字等于上一行(用rowLast表示)第j - 1个位置的数字与第j个位置的数字之和;边界情况为每一行的第一个和最后一个数字都是1,对应代码中的rowNow.add(1)分别在循环前后执行。初始化边界条件:第一行只有一个数字
1,通过代码中的List<Integer> row1 = new ArrayList<>(); row1.add(1); resultList.add(row1);实现初始化,即resultList.get(0)对应杨辉三角的第一行,初始状态为dp[0][0] = 1。求解问题:通过两层循环来求解杨辉三角。外层循环
for(int i = 1; i < numRows; i++)控制行数,内层循环for(int j = 1; j < i; j++)控制列数。根据状态转移方程逐步计算出每一行的数字,最终得到杨辉三角的前numRows行,由return resultList;返回结果。
七、Java 代码实现
class Solution {
public List<List<Integer>> generate(int numRows) {
// 创建一个用于存储结果的列表
List<List<Integer>> resultList = new ArrayList<>();
// 如果输入的行数小于等于 0,直接返回空结果列表
if (numRows <= 0) {
return resultList;
}
// 创建并初始化第一行,添加数字 1 到第一行列表中
List<Integer> row1 = new ArrayList<>();
row1.add(1);
// 将第一行添加到结果列表中
resultList.add(row1);
// 从第二行开始生成杨辉三角的后续行
for (int i = 1; i < numRows; i++) {
// 创建当前行的列表
List<Integer> rowNow = new ArrayList<>();
// 当前行的第一个数字总是 1,将其添加到当前行列表中
rowNow.add(1);
// 获取上一行的列表
List<Integer> rowLast = resultList.get(i - 1);
// 遍历当前行中间的数字(除了首尾的 1)
for (int j = 1; j < i; j++) {
// 根据上一行对应位置的数字计算当前位置的数字,即上一行当前位置的前一个数字与当前位置数字之和
rowNow.add(rowLast.get(j - 1) + rowLast.get(j));
}
// 当前行的最后一个数字总是 1,将其添加到当前行列表中
rowNow.add(1);
// 将当前行添加到结果列表中
resultList.add(rowNow);
}
// 返回生成的杨辉三角的所有行
return resultList;
}
}
在这段代码中,结果列表
resultList是一个包含多行的列表,每一行又是一个包含若干整数的列表,所以可以理解为结果列表在一定程度上类似一个二维结构,既有行也有列的概念。具体来说:
从行的角度看,
resultList中的每个元素都是一行数据,例如在生成杨辉三角的过程中,通过不断添加新的行(内部是一个整数列表)来构建整个杨辉三角。从列的角度看,每一行内部的整数列表中的元素可以看作是这一行中的不同列的值。
八、List相关
单个List<Integer>
定义
List<Integer> singleList = new ArrayList<>();List<Integer> singleList = Arrays.asList(1, 2, 3);List<Integer> singleList = new ArrayList<>(Arrays.asList(1, 2, 3));
使用
1.添加元素:
singleList.add(4);2.获取元素:
int element = singleList.get(1); // 获取索引为 1 的元素
嵌套List<List<Integer>>
在 Java 中,
List<List<Integer>>是一个嵌套的列表类型,表示一个包含多个列表的列表,其中每个内部列表中存储的元素类型为Integer。这种类型通常用于表示二维数据结构,比如矩阵、表格等。在一些场景下,当需要处理多行多列的数据,且每行的数据类型相同但行数不确定时,就可以使用这种嵌套列表的结构。
创建方法
List<List<Integer>> newList = new ArrayList<>();
添加元素方法
向外部列表添加一个新的内部列表:
List<Integer> innerList = new ArrayList<>(); innerList.add(1); innerList.add(2); nestedList.add(innerList);
向已有的内部列表添加元素:
if (!nestedList.isEmpty()) { nestedList.get(0).add(3); }
访问元素
访问外部列表中的某个内部列表:
List<Integer> specificInnerList = nestedList.get(1);
访问内部列表中的特定元素:
int element = nestedList.get(2).get(1);
遍历
使用传统的 for 循环遍历外部列表和内部列表:
for (List<Integer> innerList : nestedList) { for (Integer element : innerList) { System.out.print(element + " "); } System.out.println(); }

&spm=1001.2101.3001.5002&articleId=142388944&d=1&t=3&u=a336685846dd4f98933fb1ab1aef8e25)
91

被折叠的 条评论
为什么被折叠?



