ch9 - 动态规划(下)

本文详细介绍了动态规划在面试中常见的几种类型,包括坐标型、单序列型和双序列型,并通过具体题目如最小路径和、爬楼梯、word break、最长公共子序列等,讲解了各类动态规划问题的解决思路和方法。动态规划的核心在于状态定义和状态转移,通过这些经典题目,读者可以深入理解动态规划的应用。
摘要由CSDN通过智能技术生成

目录:

  1. 面试中常见的动态规划类型
  2. 坐标型动态规划
    1.1 题目 - 最小路径和(求最大最小值)
    1.2 题目 - 不同的路径(统计方案个数)
    1.3 题目 - 爬楼梯 (统计方案个数、一维坐标上的dp)
    1.4 题目 - jump game (是否可行、一维坐标上的dp - follow up:求最小值)
    1.5 题目 - 最长上升子序列 (最大最小值)
  3. 序列型动态规划
    2.1 题目 - word break (可行性)
    2.2 题目 - 切割回文串 palindrome-partitioning-ii (最大最小值)- 判断回文串(区间型动态规划)
  4. 双序列型动态规划
    3.1 题目 - 最长公共子序列(求Max)
    3.2 题目 - Edit Distance (求Min)
    3.3 题目 - Distinct Subsequence (求方案总数)
    3.4 题目 - Interleaving String (求是否可行)
  5. 其他类型的动态规划

0.面试中常见的动态规划类型

在这里插入图片描述

1.坐标型动态规划

初始化一个二维的动态规划的时候,首先初始化起点,紧接着初始化第0行和第0列。
在这里插入图片描述

1.1最小路径和

1)题目
http://www.lintcode.com/zh-cn/problem/minimum-path-sum/
给定一个只含非负整数的m*n网格,找到一条从左上角到右下角的可以使数字和最小的路径。

2)思路
如果是上下左右四个方向都可以走,则不能用dp,因为四个方向的话存在环,这样就不能定义远近关系,也就是不能定义大状态和小状态,就没法定义递推方程。但也存在例外,比如说滑雪的题目,按照数值降低定义远近关系。
在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    /*
     * @param grid: a list of lists of integers
     * @return: An integer, minimizes the sum of all numbers along its path
     */
    int minPathSum(vector<vector<int>> &grid) {
        // write your code here
        int n = grid.size();
        if(n==0){
            return 0;
        }
        int m = grid[0].size();

        vector<vector<int>> dp(n,vector<int>(m,INT_MAX));

        dp[0][0] = grid[0][0];
        for(int i=1;i<n;i++){
            dp[i][0] = grid[i][0] + dp[i-1][0]; 
        }
        for(int i=1;i<m;i++){
            dp[0][i] = grid[0][i] + dp[0][i-1]; 
        }

        for(int i=1;i<n;i++){
            for(int j=1;j<m;++j){
                dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1]);
            }
        }

        return dp[n-1][m-1];
    }
};

1.2 题目 - 不同的路径(统计方案个数)

1)题目
http://www.lintcode.com/zh-cn/problem/unique-paths/

有一个机器人的位于一个 m × n 个网格左上角。
机器人每一时刻只能向下或者向右移动一步。机器人试图达到网格的右下角。
问有多少条不同的路径?

follow up:
中间某些格子有障碍物。

2)思路

class Solution {
public:
    /*
     * @param m: positive integer (1 <= m <= 100)
     * @param n: positive integer (1 <= n <= 100)
     * @return: An integer
     */
    int uniquePaths(int m, int n) {
        // write your code here
        vector<vector<int>> dp(m,vector<int>(n,0));

        for(int i=0;i<n;++i){
            dp[0][i] = 1;
        }
        for(int i=0;i<m;++i){
            dp[i][0] = 1;
        }

        for(int i=1;i<m;++i){
            for(int j=1;j<n;++j){
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }

        return dp[m-1][n-1];
    }
};
class Solution {
public:
    /*
     * @param obstacleGrid: A list of lists of integers
     * @return: An integer
     */
    int uniquePathsWithObstacles(vector<vector<int>> &obstacleGrid) {
        // write your code here
        if(obstacleGrid.size()==0 || obstacleGrid[0].size() == 0){
            return 0;
        }
        int m = obstacleGrid.size();
        int n = obstacleGrid[0].size();
        vector<vector<int>> dp(m,vector<int>(n,0));

        for(int i=0;i<n;++i){
            if(obstacleGrid[0][i]==0){
                dp[0][i] = 1;
            }
            else{
                break;
            }
        }
        for(int i=0;i<m;++i){
            if(obstacleGrid[i][0]==0){
                dp[i][0] = 1;
            }
            else{
                break;
            }
        }

        for(int i=1;i<m;++i){
            for(int j=1;j<n;++j){
                if(obstacleGrid[i][j] == 1){
                    dp[i][j] = 0;
                }
                else{
                    dp[i][j] = dp[i-1][j] + dp[i][j-1];
                }
            }
        }

        return dp[m-1][n-1];
    }
};

1.3题目 - 爬楼梯 (统计方案个数)

1)题目
http://www.lintcode.com/zh-cn/problem/climbing-stairs/
假设你正在爬楼梯,需要n步你才能到达顶部。但每次你只能爬一步或者两步,你能有多少种不同的方法爬到楼顶部?

follow up:
一个小孩爬一个 n 层台阶的楼梯。他可以每次跳 1 步, 2 步 或者 3 步。实现一个方法来统计总共有多少种不同的方式爬到最顶层的台阶。

2)思路
dp[i] = dp[i-1] + dp[i-2] 斐波那契数列

class Solution {
pu
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值