動態規劃問題

變態青蛙跳臺階

問題描述:

一隻青蛙一次可以跳上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];
 }
};

 

 

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