DP

動態(tài)規(guī)劃

  1. 爬樓梯

回溯法

#include <stdio.h>

class Solution {
public:
    int climbStairs(int n) {
        if (n == 1 || n == 2){                          //遞歸出口,剩下兩節(jié)返回兩種方法
            return n;
        }
        return climbStairs(n-1) + climbStairs(n-2);     //遞歸樹分兩枝
    }
};

int main(){
    Solution solve;
    printf("%d\n", solve.climbStairs(3));   
    return 0;
}

動態(tài)規(guī)劃

第i階的方式數(shù)量 = 第i-1階方式數(shù)量 + 第i-2階方式方式數(shù)量

#include <stdio.h>

#include <vector>
class Solution {
public:
    int climbStairs(int n) {
        std::vector<int> dp(n + 3, 0);          
        dp[1] = 1;                              //邊界條件
        dp[2] = 2;
        for (int i = 3; i <= n; i++){           //寫出遞推公式
            dp[i] = dp[i-1] + dp[i-2];
        }
        return dp[n];
    }
};

int main(){
    Solution solve;
    printf("%d\n", solve.climbStairs(3));   
    return 0;
}

盜取財寶搅轿,不能盜相鄰房間

dp[i] = max(dp[i-1],dp[i-2]+nums[i])

#include <stdio.h>

#include <vector>
class Solution {
public:
    int rob(std::vector<int>& nums) {
        if (nums.size() == 0){                              //邊界條件
            return 0;
        }
        if (nums.size() == 1){
            return nums[0];
        }
        std::vector<int> dp(nums.size(), 0);                //遞推公式
        dp[0] = nums[0];
        dp[1] = std::max(nums[0], nums[1]);
        for (int i = 2; i < nums.size(); i++){
            dp[i] = std::max(dp[i-1], dp[i-2] + nums[i]);
        }
        return dp[nums.size() - 1];
    }
};

int main(){
    Solution solve;
    std::vector<int> nums;
    nums.push_back(5);
    nums.push_back(2);
    nums.push_back(6);
    nums.push_back(3);
    nums.push_back(1);
    nums.push_back(7);  
    printf("%d\n", solve.rob(nums));
    return 0;
}

最大加和序列

若dp[i-1]>0,dp[i]=dp[i-1]+nums[i]
否則dp[i]=nums[i]

#include <stdio.h>

#include <vector>
class Solution {
public:
    int maxSubArray(std::vector<int>& nums) {
        std::vector<int> dp(nums.size(), 0);
        dp[0] = nums[0];                                    //邊界條件
        int max_res = dp[0];
        for (int i = 1; i < nums.size(); i++){
            dp[i] = std::max(dp[i-1] + nums[i], nums[i]);   //遞推公式
            if (max_res < dp[i]){                           //找到dp[i]中最大的
                max_res = dp[i];
            }
        }
        return max_res;
    }
};

int main(){
    Solution solve;
    std::vector<int> nums;
    nums.push_back(-2);
    nums.push_back(1);
    nums.push_back(-3);
    nums.push_back(4);
    nums.push_back(-1);
    nums.push_back(2);
    nums.push_back(1);
    nums.push_back(-5);
    nums.push_back(4);
    printf("%d\n", solve.maxSubArray(nums));
    return 0;
}

最小數(shù)值鈔票

當(dāng)i-coins[j] >= 0且dp[i-coins[j]!=-1]時:  表示可以減去相應(yīng)的鈔票值病涨,并且減去后對應(yīng)的數(shù)組元素有值
j = 0,1,2,3,4; coins[j] = 1,2,5,7,10      
dp[i] = getmin(dp[i-coins[j]]) + 1        dp[i]就是減去一張鈔票結(jié)果的最小值加一  
#include <stdio.h>

#include <vector>

class Solution {
public:
    int coinChange(std::vector<int>& coins, int amount) {
        std::vector<int> dp;
        for (int i = 0; i <= amount; i++){
            dp.push_back(-1);
        }
        dp[0] = 0;                                                      //邊界條件  
        for (int i = 1; i <= amount; i++){
            for (int j = 0; j < coins.size(); j++){
                if (i - coins[j] >= 0 && dp[i - coins[j]] != -1){       //可以減去相應(yīng)的鈔票值,并且減去后對應(yīng)的數(shù)組元素有值
                    if (dp[i] == -1 || dp[i] > dp[i - coins[j]] + 1){   //dp[i]為-1或者dp[i]大于當(dāng)前計算的結(jié)果
                        dp[i] = dp[i - coins[j]] + 1;                   //更新dp[i]
                    }
                }
            }
        }
        return dp[amount];
    }
};

int main(){ 
    Solution solve;
    std::vector<int> coins;
    coins.push_back(1);
    coins.push_back(2);
    coins.push_back(5);
    coins.push_back(7);
    coins.push_back(10);    
    for (int i = 1; i<= 14; i++){
        printf("dp[%d] = %d\n", i, solve.coinChange(coins, i));
    }
    return 0;
}

三角形璧坟,最小路徑

dp[i][j]=min(dp[i+1][j],dp[i+1][j+1])+triangle[i][j]


#include <stdio.h>
#include <vector>

class Solution {
public:
    int minimumTotal(std::vector<std::vector<int> >& triangle){
        if (triangle.size() == 0){
            return 0;
        }
        std::vector<std::vector<int> > dp;                      //構(gòu)造dp和三角形相同
        for (int i = 0; i < triangle.size(); i++){          
            dp.push_back(std::vector<int>());
            for (int j = 0; j < triangle.size(); j++){
                dp[i].push_back(0);
            }
        }
        for (int i = 0; i < dp.size(); i++){                    //邊界條件既穆,最后一行就是triangle的值
            dp[dp.size()-1][i] = triangle[dp.size()-1][i];
        }
        for (int i = dp.size() - 2; i >= 0; i--){               //遍歷列和行
            for (int j = 0; j < dp[i].size(); j++)              
                dp[i][j] = std::min(dp[i+1][j], dp[i+1][j+1])   //遞推公式
                             + triangle[i][j];
        }
        return dp[0][0];
    }
};

int main(){
    std::vector<std::vector<int> > triangle;
    int test[][10] = {{2}, {3, 4}, {6, 5, 7}, {4, 1, 8, 3}};
    for (int i = 0; i < 4; i++){
        triangle.push_back(std::vector<int>());
        for (int j = 0; j < i + 1; j++){
            triangle[i].push_back(test[i][j]);
        }
    }
    Solution solve;
    printf("%d\n", solve.minimumTotal(triangle));
    return 0;
}

最長上升子序列

若nums[i]>nums[j]赎懦,說明nums[i]可放置在nums[j]的后面,組成最長上升子序列
若dp[i]<dp[j]+1: dp[i]=dp[j]+1

#include <stdio.h>

#include <vector>

class Solution {
public:
    int lengthOfLIS(std::vector<int>& nums) {
        if (nums.size() == 0){
            return 0;
        }
        std::vector<int> dp(nums.size(), 0);
        dp[0] = 1;
        int LIS = 1;
        for (int i = 1; i < dp.size(); i++){                    //遍歷所有
            dp[i] = 1;
            for (int j = 0; j < i; j++){                        //遍歷之前的
                if (nums[i] > nums[j] && dp[i] < dp[j] + 1){    //當(dāng)前數(shù)字能排到某序列后幻工,并且比該序列長度加一小
                    dp[i] = dp[j] + 1;
                }
            }
            if (LIS < dp[i]){
                LIS = dp[i];
            }
        }
        return LIS;
    }
};

int main(){
    int test[] = {10, 9, 2, 5, 3, 7, 101, 18};
    std::vector<int> nums;
    for (int i = 0; i < 8; i++){
        nums.push_back(test[i]);
    }
    Solution solve;
    printf("%d\n", solve.lengthOfLIS(nums));
    return 0;
}

第二種励两,用棧解決

#include <stdio.h>

#include <vector>

class Solution {
public:
    int lengthOfLIS(std::vector<int>& nums) {
        if (nums.size() == 0){
            return 0;
        }
        std::vector<int> stack;
        stack.push_back(nums[0]);
        for (int i = 1; i < nums.size(); i++){
            if (nums[i] > stack.back()){                    //比棧頂大的就入棧
                stack.push_back(nums[i]);
            }
            else{
                for (int j = 0; j < stack.size(); j++){     //否則替換棧中第一個比他大的元素  
                    if (stack[j] >= nums[i]){
                        stack[j] = nums[i];
                        break;
                    }
                }
            }
        }
        return stack.size();
    }
};

int main(){
    int test[] = {1, 3, 2, 3, 1, 4};
    std::vector<int> nums;
    for (int i = 0; i < 6; i++){
        nums.push_back(test[i]);
    }
    Solution solve;
    printf("%d\n", solve.lengthOfLIS(nums));
    return 0;
}

最小路徑之和

#include <stdio.h>

#include <vector>

class Solution {
public:
    int minPathSum(std::vector<std::vector<int> >& grid) {
        if (grid.size() == 0){
            return 0;
        }
        int row = grid.size();
        int column = grid[0].size();
        std::vector<std::vector<int> > 
                        dp(row, std::vector<int>(column, 0));
        
        dp[0][0] = grid[0][0];
        for (int i = 1; i < column; i++){                   //先初始化第一行
            dp[0][i] = dp[0][i-1] + grid[0][i];
        }
        for (int i = 1; i < row; i++){                      //初始化其他  
            dp[i][0] = dp[i-1][0] + grid[i][0];             //第一列直接加
            for (int j = 1; j < column; j++){
                dp[i][j] = std::min(dp[i-1][j], dp[i][j-1]) + grid[i][j];   //其他的要對比兩次加的結(jié)果  
            }
        }
        return dp[row-1][column-1];
    }
};

int main(){
    int test[][3] = {{1,3,1}, {1,5,1}, {4,2,1}};
    std::vector<std::vector<int> > grid;
    for (int i = 0; i < 3; i++){
        grid.push_back(std::vector<int>());
        for (int j = 0; j < 3; j++){
            grid[i].push_back(test[i][j]);
        }
    }
    Solution solve;
    printf("%d\n", solve.minPathSum(grid)); 
    return 0;
}

最長公共子序列

dp[i][j] 表示子串A[0...i](數(shù)組長度為n)和子串B[0...j](數(shù)組長度為m)的最長公共子序列

當(dāng)A[i] == B[j]時,dp[i][j] = dp[i-1][j-1] + 1;

否則囊颅,dp[i][j] = max(dp[i-1][j], dp[i][j-1]);

最優(yōu)解為dp[n-1][m-1];

https://www.cnblogs.com/fengziwei/p/7827959.html
import java.util.Scanner;
 
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            String str1 = scanner.nextLine().toLowerCase();
            String str2 = scanner.nextLine().toLowerCase();
            System.out.println(findLCS(str1, str1.length(), str2, str2.length()));
        }
    }
 
    public static int findLCS(String A, int n, String B, int m) {
        int[][] dp = new int[n + 1][m + 1];
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= m; j++) {
                dp[i][j] = 0;
            }
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                if (A.charAt(i - 1) == B.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = dp[i - 1][j] > dp[i][j - 1] ? dp[i - 1][j] : dp[i][j - 1];
                }
            }
        }
        return dp[n][m];
    }
}

股票問題

狀態(tài)轉(zhuǎn)移方程:
分為第i天不賣出和賣出
dp[k][i] = max(dp[k][i-1], dp[k-1][j]+price[i] - price[j], j屬于[0,i-1])

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末当悔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子踢代,更是在濱河造成了極大的恐慌盲憎,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胳挎,死亡現(xiàn)場離奇詭異饼疙,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)慕爬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進(jìn)店門宏多,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人澡罚,你說我怎么就攤上這事∩銮耄” “怎么了留搔?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長铛铁。 經(jīng)常有香客問我隔显,道長,這世上最難降的妖魔是什么饵逐? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任括眠,我火速辦了婚禮,結(jié)果婚禮上倍权,老公的妹妹穿的比我還像新娘掷豺。我一直安慰自己,他們只是感情好薄声,可當(dāng)我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布当船。 她就那樣靜靜地躺著,像睡著了一般默辨。 火紅的嫁衣襯著肌膚如雪德频。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天缩幸,我揣著相機(jī)與錄音壹置,去河邊找鬼竞思。 笑死,一個胖子當(dāng)著我的面吹牛钞护,可吹牛的內(nèi)容都是我干的盖喷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼患亿,長吁一口氣:“原來是場噩夢啊……” “哼传蹈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起步藕,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤惦界,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后咙冗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體沾歪,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年雾消,在試婚紗的時候發(fā)現(xiàn)自己被綠了灾搏。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡立润,死狀恐怖狂窑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情桑腮,我是刑警寧澤泉哈,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站破讨,受9級特大地震影響丛晦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜提陶,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一烫沙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧隙笆,春花似錦锌蓄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至乏冀,卻和暖如春蝶糯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辆沦。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工昼捍, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留识虚,地道東北人。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓妒茬,卻偏偏與公主長得像担锤,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子乍钻,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,107評論 2 356