zoukankan      html  css  js  c++  java
  • leetcode Ch2-Dynamic Programming [2014]

    1. Triangle

     1 class Solution {
     2 public:
     3     int minimumTotal(vector<vector<int> > &triangle) {
     4         int n=triangle.size();
     5         int* res=new int[n];
     6         for(int i=0;i<n;i++)
     7             res[i]=triangle[n-1][i];
     8         for(int i=n-2;i>=0;i--)    
     9         {
    10             for(int j=0;j<=i;j++)
    11             {
    12                 res[j]=triangle[i][j]+std::min(res[j],res[j+1]);
    13             }
    14         }
    15         return res[0];
    16     }
    17 }; 
    之前用自顶向下做的,但是用自底向上会更简单些,因为 不用考虑列数是否是第一列或最后一列,行数是否是第一行,等等这一系列问题。而且最后的结果不用再通过遍历一遍最下面一行来找最小值。

     2. unique paths

    首先是利用了滚动数组的解法:

     1  class Solution {//滚动数组
     2 public:
     3     int uniquePaths(int m, int n) {
     4         vector<int> dp(n,0);
     5         dp[0]=1;
     6         for(int i=0;i<m;i++)
     7         {
     8             for(int j=1;j<n;j++)
     9             {
    10                 dp[j]=dp[j-1]+dp[j];
    11             }
    12         }
    13         return dp[n-1];
    14     }
    15 };

    然后是普通二维dp数组的解法:

     1  class Solution {//二维dp数组
     2 public:
     3     int uniquePaths(int m, int n) {
     4         vector<vector<int>> dp(m,vector<int>(n,0));
     5         for(int i=0;i<m;i++)
     6             dp[i][0]=1;
     7         for(int i=0;i<n;i++)
     8             dp[0][i]=1;
     9         for(int i=1;i<m;i++)
    10         {
    11             for(int j=1;j<n;j++)
    12             {
    13                 dp[i][j]=dp[i-1][j]+dp[i][j-1];
    14             }
    15         }
    16         return dp[m-1][n-1];
    17     }
    18 }; 

     3. unique paths II

     首先是使用滚动数组的解法。注意与上一题中的不同。j循环中变为从0开始,因为要确保当obstacleGrid[i][0]为0时,更新dp[j]为0.

     1 class Solution {//滚动数组
     2 public:
     3     int uniquePathsWithObstacles(vector<vector<int> > &obstacleGrid) {
     4         if(obstacleGrid.size()==0) return 0;
     5         int m=obstacleGrid.size(); int n=obstacleGrid[0].size();
     6         vector<int> dp(n,0);
     7         dp[0]=1;
     8         for(int i=0;i<m;i++)
     9         {
    10             for(int j=0;j<n;j++)
    11             {
    12                 if(obstacleGrid[i][j]==1)
    13                     dp[j]=0;
    14                 else if(j>0)//j==0时就不执行了。
    15                     dp[j]=dp[j]+dp[j-1];
    16             }
    17         }
    18         return dp[n-1];
    19     }
    20 };

    使用普通二维dp数组。易错点是两层for循环都是从1开始,因为涉及到dp[j-1]。

     1 class Solution {//普通二维dp数组
     2 public:
     3     int uniquePathsWithObstacles(vector<vector<int> > &obstacleGrid) {
     4         if(obstacleGrid.size()==0) return 0;
     5         int m=obstacleGrid.size(); int n=obstacleGrid[0].size();
     6         vector<vector<int>> dp(m,vector<int>(n,0));
     7         for(int i=0;i<m;i++)
     8         {
     9             if(obstacleGrid[i][0]==1) break;
    10             else dp[i][0]=1;
    11         }
    12         for(int i=0;i<n;i++)
    13         {
    14             if(obstacleGrid[0][i]==1) break;
    15             else dp[0][i]=1;
    16         }
    17         for(int i=1;i<m;i++)//注意:从1开始
    18         {
    19             for(int j=1;j<n;j++)//注意:从1开始
    20             {
    21                 if(obstacleGrid[i][j]==1) dp[i][j]=0;
    22                 else
    23                     dp[i][j]=dp[i-1][j]+dp[i][j-1];
    24             }
    25         }
    26         return dp[m-1][n-1];
    27     }
    28 };

     4. minimum path sum

    如果不想判断临界条件,可以分配二维dp数组时多分配1行和1列,用dp[i][j]来表示从左上角到grid[i-1][j-1]的最小路径和。

    下面的解法是判断临界条件的,未采用上述技巧。

    二维dp数组:

     1 class Solution {
     2 public:
     3     int minPathSum(vector<vector<int> > &grid) {
     4         if(grid.size()==0) return 0;
     5         int m=grid.size();int n=grid[0].size();
     6         vector<vector<int>> dp(m,vector<int>(n,0));
     7         dp[0][0]=grid[0][0];
     8         for(int i=1;i<m;i++)
     9             dp[i][0]=dp[i-1][0]+grid[i][0];
    10         for(int i=1;i<n;i++)
    11             dp[0][i]=dp[0][i-1]+grid[0][i];
    12         for(int i=1;i<m;i++)
    13         {
    14             for(int j=1;j<n;j++)
    15             {
    16                 dp[i][j]=grid[i][j]+std::min(dp[i-1][j],dp[i][j-1]);
    17             }
    18         }
    19         return dp[m-1][n-1];
    20     }
    21 };

     滚动数组:

     1 class Solution {
     2 public:
     3     int minPathSum(vector<vector<int> > &grid) {
     4         if(grid.size()==0) return 0;
     5         int m=grid.size();int n=grid[0].size();
     6         vector<int> dp(n,INT_MAX);//初始值需要设成INT_MAX,因为后面有min比较。
     7         dp[0]=0;
     8         for(int i=0;i<m;i++)
     9         {
    10             dp[0]+=grid[i][0];
    11             for(int j=1;j<n;j++)
    12             {
    13                 dp[j]=grid[i][j]+std::min(dp[j],dp[j-1]);
    14             }
    15         }
    16         return dp[n-1];
    17     }
    18 };

     5. climbing stairs

     1 class Solution {
     2 public:
     3     int climbStairs(int n) {
     4         if(n==0||n==1||n==2) return n;
     5         vector<int> dp(n+1,0);
     6         dp[0]=0;dp[1]=1;dp[2]=2;
     7         for(int i=3;i<=n;i++)
     8         {
     9             dp[i]=dp[i-1]+dp[i-2];
    10         }
    11         return dp[n];
    12     }
    13 };

    用熟了之后只用3个变量就可以,不用开辟n个元素的数组。

     6. jump game

     1 class Solution {
     2 public:
     3     bool canJump(int A[], int n) {
     4         int reach=0;
     5         for(int i=0;i<=reach&&i<n;i++)
     6         {
     7             reach=std::max(reach,A[i]+i);
     8             if(reach>=n-1) return true;
     9         }
    10         return false;
    11     }
    12 };

    通过变量reach来记录当前能达到的最远位置。

    7. jump game II

     1 class Solution {
     2 public:
     3     int jump(int A[], int n) {
     4         int start=0,end=0,count=0;
     5         int max=0;
     6         if(n==1) return 0;
     7         while(end<n)
     8         {
     9             count++;
    10             for(int i=start;i<=end;i++)
    11             {
    12                 if(A[i]+i>=n-1) return count;
    13                 if(A[i]+i>max)max=A[i]+i; //max表示下一轮while循环时能遍历到的最远的地方
    14             }
    15             start=end+1;
    16             end=max;
    17         }
    18         
    19     }
    20 };

    start和end表示每一轮while循环能遍历的元素区域。每下一轮的start都是这一轮的end+1,保证了无缝衔接;每下一轮的end是这一轮中计算出的max,即(在下一轮while循环时)能遍历到的最远的地方。每个元素只被遍历一次,故复杂度为O(n)。最后能覆盖到下标为n-1的元素时所经历的while轮数即为最终答案(最少jump次数)。

    想不通时就代入实例跑一下,立马就清晰了。

     8. palindrome partitioning II

     1 class Solution {
     2 public:
     3     int minCut(string s) {
     4         const int n=s.size();
     5         vector<int> f(n+1,0);
     6         vector<vector<bool>> dp(n,vector<bool>(n,0));
     7         for(int i=0;i<n+1;i++)
     8         {
     9             f[i]=n-1-i;
    10         }
    11         for(int i=n-1;i>=0;i--)
    12         {
    13             for(int j=i;j<n;j++)
    14             {
    15                 if((i==j)||(s[i]==s[j]&&j==i+1)||(s[i]==s[j]&&dp[i+1][j-1]))//注意判断顺序
    16                 {
    17                     dp[i][j]=1;
    18                     f[i]=std::min(f[i],f[j+1]+1);
    19                 }
    20             }
    21         }
    22         return f[0];       
    23     }
    24 };

     9. word break

     1 class Solution {
     2 public:
     3     bool wordBreak(string s, unordered_set<string> &dict) {
     4         int n=s.size();
     5         if(n==0) return 0;
     6         vector<bool> dp(n+1,0);
     7         dp[0]=1;
     8         for(int i=1;i<=n;i++)//i表示当前长度(从下标0算起)
     9         {
    10             for(int k=0;k<i;k++)//k表示左半子串的长度
    11             {//通过k的变化,尝试每种分隔方式
    12                 if(dp[k]&&dict.find(s.substr(k,i-k))!=dict.end())//dp[i]表示从下标0开始的长度为i的子串是否满足word break.
    13                 {
    14                     dp[i]=1;
    15                     break;
    16                 }
    17             }
    18         }
    19         return dp[n];
    20     }
    21 };

    可参考以前写的。http://www.cnblogs.com/forcheryl/p/3997304.html

    10.  decode ways

     1 class Solution {
     2 public:
     3     int numDecodings(string s) {
     4         int n=s.size();
     5         if(n==0) return 0;
     6         vector<int> dp(n+1,0);
     7         dp[0]=1;
     8         if(isValid(s.substr(0,1)))
     9             dp[1]=1;
    10         for(int i=2;i<=n;i++)
    11         {
    12             if(isValid(s.substr(i-1,1)))
    13                 dp[i]+=dp[i-1];
    14             if(isValid(s.substr(i-2,2)))
    15                 dp[i]+=dp[i-2];
    16         }
    17         return dp[n];
    18     }
    19 private:
    20     int isValid(string s)
    21     {
    22         if(s[0]=='0') return 0;
    23         int tmp=stoi(s);
    24         return tmp>=1&&tmp<=26;
    25     }
    26 };

    关键的是先写出递推式。dp[n]=dp[n-1]*if(condition1)+dp[n-2]*if(condition2)

     这里的condition1和condition2分别是判断两个对应的子串(s[i-1]、s[i-2...i-1])是否为valid。为valid时才可以累加上。

     注意:dp[n]表示从下标0起的长度为n的子串的decode ways。

    http://okckd.github.io/blog/2014/06/24/NineChap-Dynamic-Programming/

    http://blog.csdn.net/linhuanmars/article/details/38468361

  • 相关阅读:
    Unity 3(一):简介与示例
    MongoDB以Windows Service运行
    动态SQL中变量赋值
    网站发布IIS后堆栈追踪无法获取出错的行号
    GridView Postback后出错Operation is not valid due to the current state of the object.
    Visual Studio 2010 SP1 在线安装后,找到缓存在本地的临时文件以便下次离线安装
    SQL Server 问题之 排序规则(collation)冲突
    IIS 问题集锦
    linux下安装mysql(ubuntu0.16.04.1)
    apt-get update 系列作用
  • 原文地址:https://www.cnblogs.com/forcheryl/p/4108637.html
Copyright © 2011-2022 走看看