算法-动态规划题型训练

手机软件开发 2024-9-20 17:59:43 54 0 来自 中国
Search

当一个大题目是由多个子题目构成时,我们可以通过不绝分解题目来终极构建我们想求的大题目。这个过程成为搜索(Search)。
搜索空间(Search Space)可以用Tree的形式显现出来,便于明白。
时间复杂度取决于这棵树的深度和每个node的children个数。
Search 最告急的就是界说好状态,包管每个子题目都能用一个状态来形貌
Search没有重复子题目,但DP有。
DP(Dynamic Programming)

如果我们Search Space有重复子题目的话,可以纪录下这些子题目的答案来包管不会重复计算多次。以是DP也被称为Search+Memoization
云云一来,时间复杂度就取决于子题目的个数。
全部DP都可以写成Bottom Up DFS的形式。
小技巧:界说号状态后,可以从一个中心状态出发去思索递归规则
具体来说,动态规划的一般流程就是三步:暴力的递归解法 -> 带备忘录的递归解法 -> 迭代的动态规划解法
就思索流程来说,就分为一下几步:找到状态和选择 -> 明白 dp 数组/函数的界说 -> 探求状态之间的关系
实例

/*一个呆板人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。呆板人每次只能向下大概向右移动一步。呆板人试图到达网格的右下角(在下图中标记为“Finish”)。问统共有多少条差异的路径?比方,上图是一个7 x 3 的网格。有多少大概的路径?示例1:输入: m = 3, n = 2输出: 3表明:从左上角开始,统共有 3 条路径可以到达右下角。1. 向右 -> 向右 -> 向下2. 向右 -> 向下 -> 向右3. 向下 -> 向右 -> 向右示例2:输入: m = 7, n = 3输出: 28提示:1 <= m, n <= 100题目数据包管答案小于便是 2 * 10 ^ 9 */class LeetCode62 {    public static void main(String[] args) {        //todo 动态规划-dp        System.out.println(new Solution().uniquePaths(9, 8));        System.out.println(new Solution2().uniquePaths(9, 8));        System.out.println(new Solution3().uniquePaths(9, 8));        System.out.println(new Solution4().uniquePaths(9, 8));    }    /*       思绪       思绪一:分列组合       由于呆板到底右下角,向下几步,向右几步都是固定的,       比如,m=3, n=2,我们只要向下 1 步,向右 2 步就肯定能到达止境。       以是有 C_{m+n-2}^{m-1}C       m+n−2       m−1       Python       def uniquePaths(self, m: int, n: int) -> int:               return int(math.factorial(m+n-2)/math.factorial(m-1)/math.factorial(n-1))     */    static class Solution {        public int uniquePaths(int m, int n) {            int[] cur = new int[n];            Arrays.fill(cur, 1);            for (int i = 1; i < m; i++) {                for (int j = 1; j < n; j++) {                    cur[j] += cur[j - 1];                }            }            return cur[n - 1];        }    }    static class Solution2 {        /*       思绪二:动态规划       我们令 dp[j] 是到达 i, j 最多路径       都有上一个和左一个决定       动态方程:dp[j] = dp[i-1][j] + dp[j-1]       注意,对于第一行 dp[0][j],大概第一列 dp[0],由于都是在边界,以是只能为 1       时间复杂度:O(m*n)       空间复杂度:O(m*n)       优化:由于我们每次只必要 dp[i-1][j],dp[j-1]       以是我们只要纪录这两个数,直接看代码吧!         */        public int uniquePaths(int m, int n) {            int[][] dp = new int[m][n];            for (int i = 0; i < n; i++) dp[0] = 1;            for (int i = 0; i < m; i++) dp[0] = 1;            for (int i = 1; i < m; i++) {                for (int j = 1; j < n; j++) {                    dp[j] = dp[i - 1][j] + dp[j - 1];                }            }            return dp[m - 1][n - 1];        }    }    static class Solution3 {        public int uniquePaths(int m, int n) {            int[] pre = new int[n];            int[] cur = new int[n];            Arrays.fill(pre, 1);            Arrays.fill(cur, 1);            for (int i = 1; i < m; i++) {                for (int j = 1; j < n; j++) {                    cur[j] = cur[j - 1] + pre[j];                }                pre = cur.clone();            }            return pre[n - 1];        }    }    static class Solution4 {        public int uniquePaths(int m, int n) {            int[] cur = new int[n];            Arrays.fill(cur, 1);            for (int i = 1; i < m; i++) {                for (int j = 1; j < n; j++) {                    cur[j] += cur[j - 1];                }            }            return cur[n - 1];        }    }}/*给定一个包罗非负整数的 mxn网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。阐明:每次只能向下大概向右移动一步。示例:输入:[ [1,3,1],  [1,5,1],  [4,2,1]]输出: 7表明: 由于路径 1→3→1→1→1 的总和最小。 */public class LeetCode64 {    public static void main(String[] args) {        //todo 动态规划-dp        System.out.println(new Solution().minPathSum(new int[][]{                {1, 3, 1},                {1, 5, 1},                {4, 2, 1}        }));        System.out.println(new Solution().minPathSum2(new int[][]{                {1, 3, 1},                {1, 5, 1},                {4, 2, 1}        }));    }    /*    思绪分析:    -很显着,我们在遇到如许的统计可行路径的数目,大概求最小路径的时间,比力容易想到的两种做法,一个是搜索,另一个是动态规划    -而搜索的做法,仅仅在数据规模比力小的时间才思量使用,以是在这里,我们实行接纳动态规划来解决这个题目。    动态规划,告急关注以下两点    1,状态的设置。在这个题目里,由于要求最小路径和,我们可以令dp[j]代表从(i,j)走到(m-1,n-1)点的最小路径和    2,状态转移方程。我们思量怎样来求出dp[j]。由于每次只能往右或下走,以是(i,j)只能走到(i+1,j)大概(i,j+1)。       换言之,dp[j]的前续状态只有dp[i+1][j],dp[j+1],以是我们在两者取最小,然后加上这个格子内的数即可。       dp(i,j)=grid(i,j)+min(dp(i+1,j),dp(i,j+1))     */    static class Solution {        public int minPathSum(int[][] grid) {            int[][] dp = new int[grid.length][grid[0].length];            for (int i = grid.length - 1; i >= 0; i--) {                for (int j = grid[0].length - 1; j >= 0; j--) {                    if (i == grid.length - 1 && j != grid[0].length - 1)                        dp[j] = grid[j] + dp[j + 1];                    else if (j == grid[0].length - 1 && i != grid.length - 1)                        dp[j] = grid[j] + dp[i + 1][j];                    else if (j != grid[0].length - 1 && i != grid.length - 1)                        dp[j] = grid[j] + Math.min(dp[i + 1][j], dp[j + 1]);                    else                        dp[j] = grid[j];                }            }            return dp[0][0];        }        /*        动态规划-优化方法滚动数组        我们可以用一个一维数组来取代二维数组,dp数组的巨细和行巨细雷同。        这是由于对于某个固定状态,只必要思量下方和右侧的节点。        我们就可以一行一行计算,来节流空间复杂度。         */        public int minPathSum2(int[][] grid) {            int[] dp = new int[grid[0].length];            for (int i = grid.length - 1; i >= 0; i--) {                for (int j = grid[0].length - 1; j >= 0; j--) {                    if (i == grid.length - 1 && j != grid[0].length - 1) {                        dp[j] = grid[j] + dp[j + 1];                    } else if (j == grid[0].length - 1 && i != grid.length - 1) {                        dp[j] = grid[j] + dp[j];                    } else if (j != grid[0].length - 1 && i != grid.length - 1) {                        dp[j] = grid[j] + Math.min(dp[j], dp[j + 1]);                    } else {                        dp[j] = grid[j];                    }                }            }            return dp[0];        }    }}
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-10-18 22:30, Processed in 0.128078 second(s), 32 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表