码迷,mamicode.com
首页 > 其他好文 > 详细

动态规划--LintCode简单题

时间:2016-08-09 02:04:12      阅读:1343      评论:0      收藏:0      [点我收藏+]

标签:

1、爬楼梯

题目:假设你正在爬楼梯,需要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];
    }
};

2、最长上升连续子序列

题目:给定一个整数数组(下标从 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()));
    }
};

 

3、最小路径和

题目:给定一个只含非负整数的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];   
    }};

4、栅栏染色

这道题在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;
    }
};

5、数字三角形

题目:给定一个数字三角形,找到从顶部到底部的最小路径和。每一步可以移动到下面一行的相邻数字上。

给定的三角形:[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;
    }
};

6、不同的路径I

题目:有一个机器人的位于一个M×N个网格左上角(下图中标记为‘Start‘)。机器人每一时刻只能向下或者向右移动一步。机器人试图达到网格的右下角(下图中标记为‘Finish‘)。

问有多少条不同的路径?
分析:和第一题走楼梯很像,只不过变成二维而已,同样设dp[i][j]为走到坐标(i,j)的路径总数
   则dp[i][j]=dp[i-1][j]+dp[i][j-1],到(i,j)等于该坐标的上一个坐标的路径总数加上该坐标的左一个左边的路径总数
注意:代码一开始的初始化为对该网格的第一行或第一列,初始值都为1 ,因为如果存在只有一行或一列,则情况都只有一种。
代码:
class Solution {
public:
    int uniquePaths(int m, int n) {
        // wirte your code here
        vector<vector<int>> dp(m);
        
        for(int i=0;i<m;i++)
            dp[i].resize(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];
    }
};

7、不同的路径II

题目:"不同的路径" 的跟进问题:现在考虑网格中有障碍物,那样将会有多少条不同的路径?网格中的障碍和空位置分别用 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];
    }
};

 

 第一次接触动态规划,做的也只是最基础的题,以上的思路都是早上听我老师讲完,然后晚上把代码打出来并整理了下,记录在博客中,这也是第一次写博客,希望能坚持下来。

 

动态规划--LintCode简单题

标签:

原文地址:http://www.cnblogs.com/hzrrzh/p/5751566.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!