动态规划问题

变态青蛙跳台阶

问题描述:

一只青蛙一次可以跳上1级台阶,也可以跳上2……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多

少种跳法。

思想:

利用排列组合的思想,将台阶分为两部分,前n-1是一部分,最后一节是一部分。则

前面的台阶有两种选择:跳或者不跳,最后一节台阶只有一种选择,必须跳

F(n)=f(n-1)+f(n-2)+....f(n-n)

F(n-1)=f(n-2)+f(n-3)+...+f(n-n)

F(n)=2*f(n-1)*1

import java.util.*;
public class Main {
    public static int fun(int n) {
        int total=1;
        if(n<=0){
            return 0;
        }
        for(int i=1;i<n;i++){
            total*=2;
        }
        return total;
    }
    public static void main(String[]args) {
        Scanner sc=new Scanner(System.in);
        int m=sc.nextInt();
        int ret=fun(m);
        System.out.println(ret);
    }
}

矩形覆盖

问题描述

我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

思路:

有两种放的方式:

横着放

一个矩形不能构成完整的矩形:F(i-2)种方法

竖着放

一个矩形就可以构成一个完整的矩形:F(i-1)种方法

特殊情况:当n等1时,有一种方法,等2时,有两种方法

import java.util.*;
public class Main {
    public static int fugai(int n) {
        if(n==1||n==2){
            return n;
        }
        return fugai(n-1)+fugai(n-2);
    }
    public static void main(String[]args) {
        Scanner sc=new Scanner(System.in);
        int m=sc.nextInt();
        int ret=fugai(m);
        System.out.println(ret);
    }
}

最大连续子序列和

问题描述:
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)

思路:看成两部分,前i-1项和第i项,前i-1项加上第i项的和与第i项做比较,取最大值,换言之,如果前i-1项和为负数,则最后取第i项,保证取得值最大,最后再取所有连续子序列和最大值

  public static int maxSum(int a[]) {
        int sum=a[0];
        int maxsum=a[0];
        for(int i=1;i<a.length;i++){
            sum=Math.max(sum+a[i],a[i]);
            maxsum=Math.max(sum,maxsum);
        }
        return maxsum;
    }

 

字符串分割

问题描述:

 给定一个字符串和一个词典dict,确定s是否可以根据词典中的词分成 一个或多个单词。

思路:还是将字符串看作两部分,看作前 j 部分和后 j~i-1部分,确定能分割条件是:前 j 部分能在字典中找到,后j~i-1部分也能在字典中找到

public class Main{
public boolean wordBreak(String s, List<String> wordDict) {
          int n = s.length(); //这里输入都是非空的,n >= 1
         boolean[] opt = new boolean[n + 1];
          opt[n] = true; //opt[i]表示从i到n - 1的子串是否为wordBreak。opt[n]初始化为true
          for (int i = n - 1; i >= 0; i--) {
              opt[i] = false;
              for (String item : wordDict) {
                 if (s.indexOf(item, i) == i) {
                   opt[i] = opt[i] || opt[i + item.length()];
                 }
                 
                 //如果已经为true就可以不用再匹配wordDict里的字符串了
                 if (opt[i]) {
                     break;
                 }
             }
         }
        return opt[0];
     }
     
 }

三角矩阵

问题描述:

一个三角形矩阵,从第一个元素到最后一个元素得路径最小值

思想:

每个数字可以走得都是它的所在列和后一列。

(i, j)  --->  (i+1,j),(i+1,j+1)

(i, j)  <----  (i-1,j),(i-1,j-1)

分为三种情况:

F(i,j)=min(f(i-1,j),f(i-1,j-1))+a[i][j]

F(i,0)=f(i-1,0)+a[i][0]

F(i,i)=f(i-1,i-10+a[i][i]

最后取 min(F(i,j)).

  public int minimumTotal(List<List<Integer>> triangle){
    int[] []dp = new int[triangle.size() + 1][triangle.size() + 1];
        for (int i = triangle.size() - 1; i >= 0; i--) {
        for (int j = 0; j <i; j++) {
            dp[i][j] = Math.min(dp[i-1][j], dp[i-1][j + 1]) + dp[i][j];
        }
    }
        return dp[0][0];
}

路径总数

问题描述:在一个m*n的网格的左上角有一个机器人,机器人在任何时候只能向下或者向右移动,

 机器人试图到达网格的右下角,有多少可能的路径。

思路:因为机器人只能向下和向右走,所以只需要知道到达第 (m-1,n)和第 (m,n-1)个元素的方法数即可。还是利用动态思想的方法,将路径看成两部分

状态:

 子状态:从(0,0)到达(1,0),(1,1),(2,1),...(m-1,n-1)的路径数

 F(i,j): 从(0,0)到达F(i,j)的路径数

状态递推:

 F(i,j) = F(i-1,j) + F(i,j-1)

初始化:

 特殊情况:第0行和第0列

 F(0,i) = 1

 F(i,0) = 1

返回结果:

 F(m-1,n-1)

class Solution {
public:
int uniquePaths(int m, int n) {
if (m < 1 || n < 1) {
return 0;
 }
// 申请F(i,j)空间,初始化
vector<vector<int> > ret(m, vector<int>(n, 1));
for (int i = 1; i < m; ++i) {
for (int j = 1; j < n; ++j) {
// F(i,j) = F(i-1,j) + F(i,j-1)
ret[i][j] = ret[i - 1][j] + ret[i][j - 1];
 }
 }
return ret[m - 1][n - 1];
 }
};

最小路径和:

题目描述:

 给定一个m*n的网格,网格用非负数填充,找到一条从左上角到右下角的最短路径。

 注:每次只能向下或者向右移动。

思路:还是看成两部分路径,前i-1,第i个。

状态:

 子状态:从(0,0)到达(1,0),(1,1),(2,1),...(m-1,n-1)的最短路径

 F(i,j): 从(0,0)到达F(i,j)的最短路径

状态递推:

 F(i,j) = min{F(i-1,j) , F(i,j-1)} + (i,j)

初始化:

 F(0,0) = (0,0)

 特殊情况:第0行和第0列

 F(0,i) = F(0,i-1) + (0,i)

 F(i,0) = F(i-1,0) + (i,0)

返回结果:

 F(m-1,n-1)

class Solution {
public:
int minPathSum(vector<vector<int> > &grid) {
// 如果为空或者只有一行,返回0
if (grid.empty() || grid[0].empty()) {
return 0;
 }
// 获取行和列大小
const int M = grid.size();
const int N = grid[0].size();
// F(i,j)
vector<vector<int> > ret(M, vector<int>(N, 0));
// F(0,0), F(0,i), F(i,0)初始化
ret[0][0] = grid[0][0];
for (int i = 1; i != M; ++i) {
ret[i][0] = grid[i][0] + ret[i - 1][0];
 }
for (int i = 1; i != N; ++i) {
ret[0][i] = grid[0][i] + ret[0][i - 1];
 }
// F(i,j) = min{F(i-1,j) , F(i,j-1)} + (i,j)
for (int i = 1; i < M; ++i) {
比特科技
for (int j = 1; j < N; ++j) {
ret[i][j] = grid[i][j] + min(ret[i - 1][j], ret[i][j - 1]);
 }
 }
return ret[M - 1][N - 1];
 }
};

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章