分类 动态规划 下的文章

不同路径

问题描述

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
问总共有多少条不同的路径?

不同路径.png

例如,上图是一个7 x 3 的网格。有多少可能的路径?
说明:m 和 n 的值均不超过 100。

示例 1:
输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。

  1. 向右 -> 向右 -> 向下
  2. 向右 -> 向下 -> 向右
  3. 向下 -> 向右 -> 向右

示例 2:
输入: m = 7, n = 3
输出: 28

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-paths

思路

动态规划
当i==0或者j==0时,dp[i][j]=1;
当i>1或者j>1时,dp[i][j]=dp[i][j-1]+dp[i+1][j];
最后返回dp[m-1][n-1]即可。

题解

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> dp;
        dp.resize(m);
        for(int i=0;i<m;i++){
            dp[i].resize(n);
            dp[i][0]=1;
        }
        for(int i=0;i<n;i++){
            dp[0][i]=1;
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                dp[i][j]=dp[i][j-1]+dp[i-1][j];
            }
        }
        return dp[m-1][n-1];
    }
};

解码方法

问题描述

一条包含字母 A-Z 的消息通过以下方式进行了编码:

'A' -> 1
'B' -> 2
...
'Z' -> 26
给定一个只包含数字的非空字符串,请计算解码方法的总数。

示例 1:
输入: "12"
输出: 2
解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。

示例 2:
输入: "226"
输出: 3
解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/decode-ways

思路

作者:user8973
链接:https://leetcode-cn.com/problems/two-sum/solution/dong-tai-gui-hua-fen-lei-tao-lun-by-user8973/

题解

class Solution {
public:
    int numDecodings(string s) {
        int len = s.length();
        if (len == 0 || s[0] == '0') {
            return 0;
        }
        vector<int> dp(len + 1, 0);
        dp[0] = 1; dp[1]=1;
        for (int i = 1; i < len; i++) {
            if (s[i - 1] != '0') {
                int num = (s[i - 1] - '0') * 10 + (s[i] - '0');
                if (num >= 1 && num <= 26) {
                    dp[i + 1] = ((s[i] != '0') ? dp[i - 1] + dp[i] : dp[i - 1]);
                } else if (s[i] != '0') {
                    dp[i + 1] = dp[i];
                } else return 0;
            } else if (s[i] != '0') {
                dp[i + 1] = dp[i];
            } else return 0;
        }
        return dp[len];
    }
};

不同路径 II

问题描述

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

不同路径 II.png

网格中的障碍物和空位置分别用 1 和 0 来表示。

说明:m 和 n 的值均不超过 100。

示例 1:
输入:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
输出: 2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:

  1. 向右 -> 向右 -> 向下 -> 向下
  2. 向下 -> 向下 -> 向右 -> 向右

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-paths-ii

思路

int n = obstacleGrid.size(); int m = obstacleGrid[0].size();
long long dp[n][m];注意这里用long long,用int可能会爆掉
dp[i][j]为到达obstacleGrid[i][j]的路径条数,如果obstacleGrid[i][j]==1,即obstacleGrid[i][j]为障碍物,dp[i][j]置为0;否则obstacleGrid[i][j]=obstacleGrid[i-1][j]+obstacleGrid[i][j-1];
要注意先将边界dp[i][j]单独拿出来计算。

题解

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>> &obstacleGrid) {
        int n = obstacleGrid.size();
        if (n == 0) return 0;
        int m = obstacleGrid[0].size();
        long long dp[n][m];
        dp[0][0] = obstacleGrid[0][0] == 0 ? 1 : 0;
        for (int i = 1; i < n; i++) {
            dp[i][0] = obstacleGrid[i][0] == 1 ? 0 : dp[i - 1][0];
        }
        for (int j = 1; j < m; j++) {
            dp[0][j] = obstacleGrid[0][j] == 1 ? 0 : dp[0][j - 1];
        }
        for (int i = 1; i < n; i++) {
            for (int j = 1; j < m; j++) {
                dp[i][j] = obstacleGrid[i][j] == 1 ? 0 :dp[i-1][j]+dp[i][j-1];
            }
        }
        return dp[n-1][m-1];
    }
};

最长上升子序列

问题描述

给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。

说明:
可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-increasing-subsequence

思路

建立一个tmp数组,作为到tmp[i]时上升子序列的长度,最开始将tmp初始化为1。
因为nums[0]之前没有比它更小的数,所以tmp[i]不做任何改变,为初始值1;
i从2到n-1变化时,令j从0到i-1变化,当nums[j]比num[i]小时,在tmp[j]+1中寻找最大值。

题解

class Solution {
public:
    static bool cmp(int a,int b){
        return a>b;
    }
    int lengthOfLIS(vector<int> &nums) {
        int n = nums.size();
        if (n == 0) return 0;
        vector<int> tmp(n, 1);
        for (int i = 1; i < n; i++) {
            int cur = nums[i];
            for (int j = 0; j < i; j++) {
                if (cur > nums[j]) {
                    tmp[i] = max(tmp[j] + 1, tmp[i]);
                }
            }
        }
        sort(tmp.begin(), tmp.end(), cmp);
        return tmp[0];
    }
};

不同的二叉搜索树

问题描述

给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?

示例:

输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-binary-search-trees

思路

由i个不同数字组成的二叉搜索树的数量,只与数字的数量i有关,与数的大小无关。
dp[i]代表n个节点数的树的种数。dp[0]、dp[1]均为1;
求n个节点构成的树的种类时,for(int j=1;j<=i;j++){dp[i]+=dp[j-1]*dp[i-j];},表示根节点为1
的时候树的种类加上根节点为2...一直加到根节点为n的树的种类。
外层循环for(int i=2;i<=n;i++)为了求出每次的dp[j-1]*dp[i-j]。

题解

class Solution {
public:
    int numTrees(int n) {
        vector<int>dp(n+1,0);
        dp[0]=dp[1]=1;
        for(int i=2;i<=n;i++){
            for(int j=1;j<=i;j++){
                dp[i]+=dp[j-1]*dp[i-j];
            }
        }
        return dp[n];
    }
};