• 动态规划2 坐标型动态规划


    题目1

    https://www.lintcode.com/problem/unique-paths-ii/description

     1 class Solution {
     2 public:
     3     /**
     4      * @param obstacleGrid: A list of lists of integers
     5      * @return: An integer
     6      */
     7     int uniquePathsWithObstacles(vector<vector<int>> &obstacleGrid) {
     8         // write your code here
     9         int m = obstacleGrid.size();
    10         int n = obstacleGrid[0].size();
    11         
    12         if(m==0 || n==0){
    13             return 0;
    14         }
    15         
    16         int dp[m][n];
    17         
    18         /*
    19         // 数组使用new
    20         int **dp = new int *[n];
    21         for(int i=0; i<m; i++)
    22             dp[i] = new int[m];
    23         */
    24         
    25         // 初始化
    26         if(obstacleGrid[0][0]==1){
    27             dp[0][0] = 0;
    28         }else{
    29             dp[0][0] = 1;
    30         }
    31         
    32         for(int i=1; i<m; i++){
    33             if(obstacleGrid[i][0]==1){
    34                 dp[i][0] = 0;
    35             }else{
    36                 dp[i][0] = 0;
    37                 dp[i][0] = dp[i][0]+ dp[i-1][0];
    38             }
    39         }
    40         for(int j=1; j<n; j++){
    41             if(obstacleGrid[0][j]==1){
    42                 dp[0][j] = 0;
    43             }else{
    44                 dp[0][j] = 0;
    45                 dp[0][j] = dp[0][j] + dp[0][j-1];
    46             }
    47         }
    48         
    49         for(int i=1; i<m; i++){
    50             for(int j=1; j<n; j++){
    51                 if(obstacleGrid[i][j]==1){
    52                     dp[i][j] = 0;
    53                 }else{
    54                     dp[i][j] = dp[i-1][j] + dp[i][j-1];
    55                 }
    56             }
    57         }
    58         
    59         return dp[m-1][n-1];
    60     }
    61 };

    代码对比

    class Solution {
    public:
        /**
         * @param obstacleGrid: A list of lists of integers
         * @return: An integer
         */
        int uniquePathsWithObstacles(vector<vector<int>> &obstacleGrid) {
            // write your code here
            int m = obstacleGrid.size();
            int n = obstacleGrid[0].size();
            
            if(m==0 || n==0){
                return 0;
            }
            
            int dp[m][n];
            
            for(int i=0; i<m; i++){
                for(int j=0; j<n; j++){
                    if(obstacleGrid[i][j] == 1){
                        dp[i][j] = 0;
                    }else{
                        if(i==0 && j==0){  // 遇见石头直接返回0,其后一个数字等于前一个数组加这个数组,所以第一行和第一列不全是1
                            dp[i][j] = 1;
                        }else{
                            dp[i][j]=0;
                            if(i-1>=0){  // 有上边
                                dp[i][j] += dp[i-1][j];
                            }
                            
                            if(j-1>=0){  // 有左边
                                dp[i][j] += dp[i][j-1];
                            }
                        }
                    }
                }
            }
            
            return dp[m-1][n-1];
        }
    };

    题目2:LintCode 515 Paint House

    https://www.lintcode.com/problem/paint-house/description

    序列+状态

     1 class Solution {
     2 public:
     3     /**
     4      * @param costs: n x 3 cost matrix
     5      * @return: An integer, the minimum cost to paint all houses
     6      */
     7     
     8     // 不用写min函数 
     9     // int min(int x, int y){
    10     //     if(x<y){
    11     //         return x;
    12     //     }
    13     //     return y;
    14     // }
    15     
    16     
    17     // 当我们不知道如何选择状态的时候,就要用开辟数组来记录。
    18     int minCost(vector<vector<int>> &costs) {
    19         // write your code here
    20         int n = costs.size();
    21         if(n==0){
    22             return 0;
    23         }
    24         
    25         // const int INF = 0x3f3f3f3f;
    26         
    27         int dp[n+1][3];   // dp[i][j] 表示油漆前i个房子并且房子i-1是红色、蓝色、绿色的最小花费分别为dp[i][0] dp[i][1] dp[i][2]
    28         
    29         dp[0][0] = dp[0][1] = dp[0][2] = 0;
    30         
    31         for(int i=1; i<=n; i++){  // i表示房子的序号
    32         
    33             // 当第i个房子选择红色的时候,最前i个房子的最小值
    34             // dp[i][0] = INF;  
    35             dp[i][0] = min(dp[i-1][1]+costs[i-1][0], dp[i-1][2]+costs[i-1][0]);
    36             
    37             // 当第i个房子选蓝色的时候,最前i个房子的最小值
    38             // dp[i][1] = INF;  // 初始化
    39             dp[i][1] = min(dp[i-1][0]+costs[i-1][1], dp[i-1][2]+costs[i-1][1]);
    40             
    41             // 当第i个房子选择绿色的时候,最前i个房子的最小值
    42             // dp[i][2] = INF;  // 初始化
    43             dp[i][2] = min(dp[i-1][0]+costs[i-1][2], dp[i-1][1]+costs[i-1][2]);
    44         }
    45         
    46         int res = min(dp[n][0], dp[n][1]);
    47         res =  min(res, dp[n][2]);
    48         
    49         return res;
    50     }
    51 };

    题目3:LintCode 512 Decode Ways

    https://www.lintcode.com/problem/decode-ways/description

    解密字符串,划分型。

    最后一个字母,考虑是否和前面一直字母进行合并处理,此时就有了两种解密方式

    即: 前n-1n-2字符的解密方式  考虑着两种方式。

    设字符串s前i个字符解密成字母串有f[i]中方式

    dp[i] = dp[i-1] + dp[i-2]

    初始条件:dp[0]=1 空串有一种方式解密                        最值就是dp[0]=0

     1 class Solution {
     2 public:
     3     /**
     4      * @param s: a string,  encoded message
     5      * @return: an integer, the number of ways decoding
     6      */
     7     int numDecodings(string &s) {
     8         // write your code here
     9         int n = s.length();
    10         if(n == 0){
    11             return 0;
    12         }
    13         
    14         int dp[n+1];  // 0~n 前i个 数组是从0~n-1的
    15         dp[0] = 1; //有多少种方式 只有在变化的时候才起+1
    16         
    17         for(int i=1; i<=n; i++){
    18             dp[i] = 0;
    19             
    20             int tmp = s[i-1] - '0';
    21             if(tmp>=1 && tmp<=9){
    22                 dp[i] += dp[i-1];
    23             }
    24             
    25             if(i>=2){  // 控制数组不用越界
    26                 tmp = (s[i-2]-'0')*10 + (s[i-1]-'0');
    27                 if(tmp>=10 && tmp<=26){
    28                     dp[i] += dp[i-2];
    29                 }
    30             }
    31             
    32         }
    33         
    34         return dp[n];
    35     }
    36 };

    https://www.nowcoder.com/practice/b83b126603dd4e63bc4287d32d754886?tpId=98&tqId=32868&tPage=3&rp=3&ru=/ta/2019test&qru=/ta/2019test/question-ranking

    牛客笔试题目:解码方式

     1 #include <iostream>
     2 #include <cstring>
     3 
     4 using namespace std;
     5 
     6 int main(){
     7     // freopen("test.txt", "r", stdin);
     8     string s;
     9     cin >> s;
    10     // cout << s << endl;
    11     int n = s.length();
    12     
    13     int dp[n+1];  // dp[i]前i个子串解码的方式
    14     memset(dp, 0, sizeof(dp));
    15     dp[0] = 1;
    16     for(int i=1; i<=n; i++){
    17         
    18         int num = s[i-1]-'0';
    19         if(num>=1 && num<=9){
    20             dp[i] += dp[i-1];
    21         }
    22         
    23         if(i>=2){
    24             num = (s[i-2]-'0')*10 + (s[i-1]-'0');
    25             if(num>=10 && num<=26){
    26                 dp[i] = dp[i] + dp[i-2];
    27             }
    28         }
    29     }
    30     
    31     cout << dp[n] << endl;
    32     return 0;
    33 }

    牛客笔试:跳格子

    状态:dp[i] 表示调到第i个格子的方式

    初始条件:dp[1] = 1 格子数从1到n;当只有一个格子的时候条的方法数也就1; 这里dp[0]=1是为了计算方便。

     1 #include <iostream>
     2 #include <cstring>
     3 
     4 using namespace std;
     5 
     6 int main(){
     7     // freopen("test.txt", "r", stdin);
     8     int n;
     9     cin >> n;
    10     int dp[n+1];
    11     memset(dp, 0, sizeof(dp));
    12     dp[0] = 1;
    13     for(int i=1; i<=n; i++){
    14         dp[i] += dp[i-1];
    15         if(i>=2)
    16             dp[i] += dp[i-2];
    17     }
    18     cout << dp[n] << endl;
    19     return 0;
    20 }

    题目4:LintCode 397 最长连续单调子序列

    https://www.lintcode.com/problem/longest-continuous-increasing-subsequence/description

    确定状态:a[j]=1.

    f[j]:以j结尾的最长上升子序列长度

    f[j] = max{1, f[j-1]+1|j>0 and }

    答案不一定是f[n]   max{dp[0], dp[1], ..., dp[n]}

    时间复杂度O(n)   空间复杂度O(n)

    dp[i] 表示以a[i]结尾的最长连续上升子序列的长度

     1 class Solution {
     2 public:
     3     /**
     4      * @param A: An array of Integer
     5      * @return: an integer
     6      */
     7     int result = 0;
     8     
     9     // 注意这里传入的是向量数组而不是单个数组
    10     void calc(vector<int> &A, int n){
    11         int dp[n];
    12         for(int i=0; i<n; i++){
    13             dp[i] = 1;  // 初始化
    14             
    15             if(i>0 && A[i-1]<A[i]){
    16                 dp[i] = dp[i-1]+1;
    17             }
    18             
    19             if(dp[i] > result){
    20                 result = dp[i];
    21             }
    22         }
    23     }
    24     
    25     int longestIncreasingContinuousSubsequence(vector<int> &A) {
    26         // write your code here
    27         int n = A.size();
    28         if(n==0){
    29             return 0;
    30         }
    31         
    32         calc(A, n);
    33         // 反转A
    34         int i, j, t;
    35         i = 0;
    36         j= n-1;
    37         while(i<j){
    38             t = A[i];
    39             A[i] = A[j];
    40             A[j] = t;
    41             i++;
    42             j--;
    43         }
    44         
    45         
    46         calc(A, n);
    47         
    48         return result;
    49     }
    50 };

    空间复杂度O(1)  滚动数组

     1 class Solution {
     2 public:
     3     /**
     4      * @param A: An array of Integer
     5      * @return: an integer
     6      */
     7     int result = 0;
     8     
     9     // 注意这里传入的是向量数组而不是单个数组
    10     void calc(vector<int> &A, int n){
    11         int old, now = 0;
    12         int dp[2];
    13         
    14         for(int i=0; i<n; i++){
    15             old = now;
    16             now = 1-now; // 在0,1,0,1之间徘徊
    17             
    18             dp[now] = 1; // // 初始化  数组从1开始 0,1,0,1处理
    19             
    20             if(i>0 && A[i-1]<A[i]){
    21                 dp[now] = dp[old]+1;
    22             }
    23             
    24             if(dp[now] > result){
    25                 result = dp[now];
    26             }
    27         }
    28     }
    29     
    30     int longestIncreasingContinuousSubsequence(vector<int> &A) {
    31         // write your code here
    32         int n = A.size();
    33         if(n==0){
    34             return 0;
    35         }
    36         
    37         calc(A, n);
    38         // 反转A
    39         int i, j, t;
    40         i = 0;
    41         j= n-1;
    42         while(i<j){
    43             t = A[i];
    44             A[i] = A[j];
    45             A[j] = t;
    46             i++;
    47             j--;
    48         }
    49         
    50         
    51         calc(A, n);
    52         
    53         return result;
    54     }
    55 };

    牛客题目:回文字符串

    https://www.nowcoder.com/practice/5bfb74efcd5449e69a480550b1fef431?tpId=98&tqId=32846&tPage=1&rp=1&ru=/ta/2019test&qru=/ta/2019test/question-ranking

    设dp[i]:表示以a[i]结尾的回文子串的长度

    解法区间动态规划

    题目5:LintCode 110 Minimum Path Sum

    路径上的格子数字和最小

    输出最小数字和

    最值型动态规划

    dp[i][j] = min{dp[i-1][j], dp[i][j-1]} 

    初始条件 dp[0][0]=A[0][0]

    滚动数组优化空间时间复杂度 dp[0][0...n-1] 和 dp[1][0...n-1]

    只依赖于上一行,来计算下一行。

     1 class Solution {
     2 public:
     3     /**
     4      * @param grid: a list of lists of integers
     5      * @return: An integer, minimizes the sum of all numbers along its path
     6      */
     7     int minPathSum(vector<vector<int>> &A) {
     8         // write your code here
     9         const int INF = 0x3f3f3f3f;
    10         int m = A.size();
    11         int n = A[0].size();
    12         if(m==0 && n==0){
    13             return 0;
    14         }
    15         
    16         int dp[2][n];
    17         int t1, t2;
    18         int old=1, now=0;
    19         for(int i=0; i<m; i++){  // m行
    20             old = now;
    21             now = 1 - now;
    22             for(int j=0; j<n; j++){  // n列
    23                 if(i==0 && j==0){ // 初始条件
    24                     dp[now][j] = A[i][j];
    25                     continue;
    26                 }
    27                 
    28                 dp[now][j] = A[i][j];
    29                 if(i>0){
    30                     t1 = dp[old][j];
    31                 }else{
    32                     t1 = INF;
    33                 }
    34                 
    35                 if(j>0){
    36                     t2 = dp[now][j-1];
    37                 }else{
    38                     t2 = INF;
    39                 }
    40                 
    41                 if(t1<t2){
    42                     dp[now][j] += t1;
    43                 }else{
    44                     dp[now][j] += t2;
    45                 }
    46                 
    47             }
    48         }
    49         
    50         return dp[now][n-1];  // 计算完之后的答案始终在now一行。
    51     }
    52 };

     

    不使用滚动数组

     1 class Solution {
     2 public:
     3     /**
     4      * @param grid: a list of lists of integers
     5      * @return: An integer, minimizes the sum of all numbers along its path
     6      */
     7     int minPathSum(vector<vector<int>> &A) {
     8         // write your code here
     9         const int INF = 0x3f3f3f3f;
    10         int m = A.size();
    11         int n = A[0].size();
    12         if(m==0 && n==0){
    13             return 0;
    14         }
    15         
    16         int dp[m][n];
    17         
    18         // 初始化
    19         dp[0][0] = A[0][0];
    20         for(int i=1; i<m; i++){
    21             dp[i][0] = dp[i-1][0]+A[i][0];
    22         }
    23         for(int j=1; j<n; j++){
    24             dp[0][j] = dp[0][j-1]+A[0][j];
    25         }
    26         
    27         
    28         // dp计算
    29         for(int i=1; i<m; i++){
    30             for(int j=1; j<n; j++){
    31                 dp[i][j] = min(dp[i][j-1], dp[i-1][j]) + A[i][j];
    32             }
    33         }
    34         
    35         return dp[m-1][n-1];  // 计算完之后的答案始终在now一行。
    36     }
    37 };

    题目6:LintCode 553 Bomb Enemy

    https://www.lintcode.com/problem/bomb-enemy/description

    要炸死多个敌人,每个炸弹可以炸四个方向传播爆炸力。

    简化分析一个方向

    假设空地和敌人都可以放炸弹

    dp[i][j] = 0                  墙

    dp[i][j] = dp[i-1][j]        空地

    dp[i][j] = dp[i-1][j]+1     敌人

    (i,j)是空地  炸死的敌人数 

             dp_up[i][j] + dp_down[i][j] + dp_left[i][j] + dp_right[i][j]

      1 class Solution {
      2 public:
      3     /**
      4      * @param grid: Given a 2D grid, each cell is either 'W', 'E' or '0'
      5      * @return: an integer, the maximum enemies you can kill using one bomb
      6      */
      7     int maxKilledEnemies(vector<vector<char>> &A) {
      8         // write your code here
      9         
     10         int m = A.size();
     11         if(m==0){
     12             return 0;
     13         }
     14         int n = A[0].size();
     15         if(n==0){
     16             return 0;
     17         }
     18         
     19         int dp[m][n], res[m][n];
     20         
     21         for(int i=0; i<m; i++){
     22             for(int j=0; j<n; j++){
     23                 res[i][j] = 0;
     24             }
     25         }
     26         
     27         // up
     28         for(int i=0; i<m; i++){
     29             for(int j=0; j<n; j++){
     30                 if(A[i][j]=='W'){
     31                     dp[i][j] = 0;
     32                 }else{
     33                     
     34                     // 初始化值
     35                     dp[i][j] = 0;
     36                     if(A[i][j]=='E'){
     37                         dp[i][j] = 1;
     38                     }
     39                     
     40                     
     41                     // dp计算   上一行的值
     42                     if(i-1>=0){
     43                         dp[i][j] += dp[i-1][j];
     44                     }
     45                     
     46                     
     47                 }
     48                 
     49                 res[i][j] += dp[i][j];
     50             }
     51         }
     52         
     53         // down
     54         for(int i=m-1; i>=0; i--){
     55             for(int j=0; j<n; j++){
     56                 if(A[i][j]=='W'){
     57                     dp[i][j] = 0;
     58                 }else{
     59                     
     60                     // 初始化值
     61                     dp[i][j] = 0;
     62                     if(A[i][j]=='E'){
     63                         dp[i][j] = 1;
     64                     }
     65                     
     66                     
     67                     // dp计算   下一行的值
     68                     if(i+1<m){
     69                         dp[i][j] += dp[i+1][j];
     70                     }
     71                     
     72                     
     73                 }
     74                 
     75                 res[i][j] += dp[i][j];
     76             }
     77         }
     78         
     79         // lef
     80         for(int i=0; i<m; i++){
     81             for(int j=0; j<n; j++){
     82                 if(A[i][j]=='W'){
     83                     dp[i][j] = 0;
     84                 }else{
     85                     
     86                     // 初始化值
     87                     dp[i][j] = 0;
     88                     if(A[i][j]=='E'){
     89                         dp[i][j] = 1;
     90                     }
     91                     
     92                     
     93                     // dp计算   左一行的值
     94                     if(j-1>=0){
     95                         dp[i][j] += dp[i][j-1];
     96                     }
     97                     
     98                     
     99                 }
    100                 
    101                 res[i][j] += dp[i][j];
    102             }
    103         }
    104         
    105         // right
    106         for(int i=0; i<m; i++){
    107             for(int j=n-1; j>=0; j--){
    108                 if(A[i][j]=='W'){
    109                     dp[i][j] = 0;
    110                 }else{
    111                     
    112                     // 初始化值
    113                     dp[i][j] = 0;
    114                     if(A[i][j]=='E'){
    115                         dp[i][j] = 1;
    116                     }
    117                     
    118                     
    119                     // dp计算   下一行的值
    120                     if(j+1<n){
    121                         dp[i][j] += dp[i][j+1];
    122                     }
    123                     
    124                     
    125                 }
    126                 
    127                 res[i][j] += dp[i][j];
    128             }
    129         }
    130         
    131         int result = 0;
    132         for(int i=0; i<m; i++){
    133             for(int j=0; j<n; j++){
    134                 if(A[i][j] == '0'){
    135                     if(res[i][j] > result){
    136                         result = res[i][j];
    137                     }
    138                 }
    139             }
    140         }
    141         return result;
    142         
    143     }
    144 };

    序列+位操作型动态规划

    位操作:

    • & 与
    • | 或
    • 异或
    • !非

    题目7:LintCode 664 Counting Bits

     dp[i]表示i的二进制表示中有多少个1

    和位操作相关的动态规划一般用值作状态

    dp[i]表示i的二进制表示中有多少个1

    dp[i] = dp[i>>1]+(i mod 2)   // 右移一位就是除以2     (i mod 2)看最后一位是0还是1

    dp[0] = 0

    时间复杂度O(NlogN)    空间复杂度O(n)

     1 class Solution {
     2 public:
     3     /**
     4      * @param num: a non negative integer number
     5      * @return: an array represent the number of 1's in their binary
     6      */
     7     vector<int> countBits(int num) {
     8         // write your code here
     9         int dp[num+1];
    10         dp[0] = 0;
    11         for(int i=1; i<=num; i++){
    12             dp[i] = dp[i>>1] + (i%2);
    13         }
    14         
    15         
    16         vector<int> a;
    17         for(int i=0; i<=num; i++){
    18             a.push_back(dp[i]);
    19         }
    20         return a;
    21     }
    22 };
  • 相关阅读:
    QT生成流水账号
    Qt实现端口扫描器
    Qtablevies获取内容
    Qt中暂停线程的执行
    Qt经典出错信息之undefined reference to `vtable for classname
    Qt中 QString 和int, char等的“相互”转换
    caffe实现自己的层
    获取minist数据并转换成lmdb
    命名空间下接类,比如common.cpp
    caffe这个c++工程的目录结构
  • 原文地址:https://www.cnblogs.com/JCcodeblgos/p/11445556.html
Copyright © 2020-2023  润新知