标签:
题目:假设你正在爬楼梯,需要n步你才能到达顶部。但每次你只能爬一步或者两步,你能有多少种不同的方法爬到楼顶部?
分析:一次只能爬一步或者两步,所以走i步可由走i-1步的方法数和走i-2步的方法数相加获得;
设dp[i]为走i步的方法数目,则dp[i]=dp[i-1]+dp[i-2];
注意:边界问题,由上面的方程可知道 i 由2开始,且dp[0]=dp[1]=1;
代码:
class Solution {
public:
/**
dp[i]=dp[i-1]+dp[i-2]
*/
int climbStairs(int n) {
vector<int> dp(n+1,0);
//边缘
dp[0]=1;
dp[1]=1;
for(int i=2;i<=n;i++)
dp[i]=dp[i-1]+dp[i-2];
return dp[n];
}
};
题目:给定一个整数数组(下标从 0 到 n-1, n 表示整个数组的规模),请找出该数组中的最长上升连续子序列。(最长上升连续子序列可以定义为从右到左或从左到右的序列。)
分析:从左到右:设数组a为该数组,dp[i]存储前 i 个的数总和 则 if(a[i]>a[i-1]) dp[i]=dp[i-1]+value,i从1开始
从右到左:同样,不过判断为a[i]<a[i+1] dp[i]=dp[i+1]+value,i从n-2开始
代码:
#include<algorithm>
class Solution {
public:
/**
从左到右:if(a[i]>a[i-1]) dp[i]=dp[i-1]+value;
从右到左:if(a[i]>a[i+1]) dp[i]=dp[i+1]+value;
*/
int longestIncreasingContinuousSubsequence(vector<int>& A) {
// Write your code here
if(A.empty()) return 0;
int a=(int)A.size();
vector<int> dp(a,1);
for(int i=1;i<a;i++)
{
if(A[i]>A[i-1])
dp[i]=dp[i-1]+1;
}
vector<int> dp1(a,1);
for(int i=a-2;i>=0;i--)
{
if(A[i]>A[i+1])
dp1[i]=dp1[i+1]+1;
}
return max(*max_element(dp.begin(),dp.end()),
*max_element(dp1.begin(),dp1.end()));
}
};
题目:给定一个只含非负整数的m*n网格,找到一条从左上角到右下角的可以使数字和最小的路径。
分析:由条件可知道只能往下走或往右走,设dp[i][j]为走到(i,j)的最小路径总和
则dp[i][j]=min(dp[i-1][j],dp[i][j-1])+value[i][j];
注意:i,j的初始值不同会出现边界问题
代码:
class Solution {
public:
int minPathSum(vector<vector<int> > &grid) {
// write your code here
int n=(int)grid.size();
int m=(int)grid[0].size();
if(grid.empty()) return 0;
vector<vector<int>> dp(n+1);
for(int i=0;i<=n;i++)
dp[i].resize(m+1,INT_MAX);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(i==1 && j==1)
{
dp[i][j]=grid[i-1][j-1];
continue;
}
dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i-1][j-1];
}
return dp[n][m];
}};
这道题在LintCode上题目与给定数据所获得的结果不一样,如果按给定数据来看,则题目应该是:
我们有一个栅栏,它有n
个柱子,现在要给柱子染色,有k
种颜色可以染。必须保证最多两个相邻的柱子颜色不同,求有多少种染色方案
分析:最多两个相邻的柱子不同,也就是不能出现三个相同颜色的柱子;
设dp[i][j]为前 i 个柱子 染 第 j 种颜色的情况,则 if(t!=j) dp[i][t]+=dp[i-1][j]+dp[i-2][j];最后方案总数则为sum(dp[n][j]), j共k种颜色;
注意:边界
代码:
class Solution {
public:
int numWays(int n, int k) {
// Write your code here
vector<vector<int>> dp(n);
if(n==0)
return 0;
if(n==1)
return k;
if(k==1 && n>2)
return 0;
for(int i=0;i<n;i++)
dp[i].resize(k);
for(int i=0;i<k;i++)
{
dp[0][i]=1;
dp[1][i]=k;
}
for(int i=2;i<n;i++)
for(int j=0;j<k;j++)
for(int t=0;t<k;t++)
{
if(t!=j)
dp[i][t]+=dp[i-1][j]+dp[i-2][j];
}
int sum=0;
for(int j=0;j<k;j++)
{
sum+=dp[n-1][j];
}
return sum;
}
};
题目:给定一个数字三角形,找到从顶部到底部的最小路径和。每一步可以移动到下面一行的相邻数字上。
给定的三角形:[2],[3,4], [6,5,7], [4,1,8,3].
分析:题目的三角形存储在vector<vector<int>> t的二维数组中,则设dp[i][j]为t[0][0]到(i,j)的最小路径和
且 dp[i][j] = min(dp[i-1][j], dp[i-1][j+1]) + t[i][j]
注意:以上述三角形为例,当求dp[2][0]也就是到t[2][0]的最小路径和时,会发现只能从t[1][0]走到t[2][0],这是一个判断情况;
当求dp[2][2]也就是到t[2][2]的最小路径和时,会发现只能从t[1][1]走到t[2][2],这也是一个判断情况;
代码:
class Solution {
public:
int minimumTotal(vector<vector<int> > &triangle) {
int n = triangle.size();
vector<vector<int>> dp(n);
for (int i = 0; i < n; ++i)
{
dp[i].resize(n);
}
dp[0][0] = triangle[0][0];
for (int i = 1; i < n; ++i)
{
for (int j = 0; j <= i; ++j)
{
if (j == 0)
{
dp[i][j] = dp[i - 1][j] + triangle[i][j];
}
else if (j == i)
{
dp[i][j] = dp[i - 1][j - 1] + triangle[i][j];
}
else
{
dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - 1])+triangle[i][j];
}
}
}
int m = INT_MAX;
for (int i = 0; i < n; ++i) {
m = min(dp[n - 1][i], m);
}
return m;
}
};
题目:有一个机器人的位于一个M×N个网格左上角(下图中标记为‘Start‘)。机器人每一时刻只能向下或者向右移动一步。机器人试图达到网格的右下角(下图中标记为‘Finish‘)。
题目:"不同的路径" 的跟进问题:现在考虑网格中有障碍物,那样将会有多少条不同的路径?网格中的障碍和空位置分别用 1 和 0 来表示。
分析:多了障碍也就是存在路径无效,设dp[i][j]=dp[i-1][j]+dp[i][j-1];dp[i][j]=1表示没有障碍。
方程和上题目一样,不过有多了判断情况,一个是在初始化时,dp[0][0]=1只有网格的t[0][0]=0时才能赋值,然后对第一行或第一列的赋值则为只有t[i][0]==0或t[0][i]==0时,dp[i][0]=dp[i-1][0]或dp[0][i]=dp[0][i-1];
这里说明一下为什么是dp[i][0]=dp[i-1][0]或dp[0][i]=dp[0][i-1],因为在代码中一开始对dp[i][j]的初始化为0,然后再进行判断,若t[i][0]或
t[0][i]=0,则dp[i][0]或dp[0][i]等于前一个dp,因为若这是第一行或第一列,所以dp[i][0]或dp[0][i]只能由上一个dp来决定。
代码:
class Solution {
public:
/**
dp[i][j]+=dp[i-1][j]+dp[i][j-1];
value[i-1][j]==0;
value[i][j-1]==0;
*/
int uniquePathsWithObstacles(vector<vector<int> > &obstacleGrid) {
// write your code here
int n=obstacleGrid.size();
int m=obstacleGrid[0].size();
vector<vector<int>> dp(n);
for(int i=0;i<n;i++)
{
dp[i].resize(m,0);
}
if(obstacleGrid[0][0]==0)
dp[0][0]=1;
for(int i=1;i<m;i++)
{
if(obstacleGrid[0][i]==0)
dp[0][i]=dp[0][i-1];
}
for(int i=1;i<n;i++)
{
if(obstacleGrid[i][0]==0)
dp[i][0]=dp[i-1][0];
}
for(int i=1;i<n;i++)
for(int j=1;j<m;j++)
{
if(obstacleGrid[i][j]==1)
continue;
if(obstacleGrid[i-1][j]==0)
dp[i][j]+=dp[i-1][j];
if(obstacleGrid[i][j-1]==0)
dp[i][j]+=dp[i][j-1];
}
return dp[n-1][m-1];
}
};
第一次接触动态规划,做的也只是最基础的题,以上的思路都是早上听我老师讲完,然后晚上把代码打出来并整理了下,记录在博客中,这也是第一次写博客,希望能坚持下来。
标签:
原文地址:http://www.cnblogs.com/hzrrzh/p/5751566.html