数据结构与算法——动态规划

1.内容概述

在这里插入图片描述

2.爬楼梯

2.1 题目描述

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1+ 12.  2 阶

示例 2:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1+ 1+ 12.  1+ 23.  2+ 1

2.算法思想

在这里插入图片描述在这里插入图片描述

2.3 代码实现

class Solution {
public:
    int climbStairs(int n) {
        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];
    }
};

3.打家劫舍

3.1 题目描述

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

示例 1:

输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

示例 2:

输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12

3.2 算法思路

在这里插入图片描述在这里插入图片描述

3.3 代码实现

class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.size()==1){
            return nums[0];
        }
        if(nums.size()==2){
            return max(nums[0],nums[1]);
        }

        vector<int> dp(nums.size(),0);
        dp[0]=nums[0];
        dp[1]=max(nums[0],nums[1]);

        for(int i=2;i<nums.size();i++){
            dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
        }
        return dp[nums.size()-1];
    }
private:
    int max(int a,int b){
        return (a>b)?a:b;
    }
};

4.最大子序和

4.1 题目描述

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:

输入:nums = [1]
输出:1

示例 3:

输入:nums = [0]
输出:0

示例 4:

输入:nums = [-1]
输出:-1

示例 5:

输入:nums = [-100000]
输出:-100000

4.2 算法思路

在这里插入图片描述

4.3 代码思路

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        vector<int> dp(nums.size(),0);
        dp[0]=nums[0];
        int max=dp[0];
        for(int i=1;i<nums.size();i++){
            dp[i]=Max(nums[i]+dp[i-1],nums[i]);
            if(dp[i]>max){
                max=dp[i];
            }
        }
        return max;
    }
private:
    int Max(int a,int b){
        return (a>b)?a:b;
    }
};

5. 零钱兑换

5.1 题目描述

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

你可以认为每种硬币的数量是无限的。

示例 1:

输入:coins = [1, 2, 5], amount = 11
输出:3 
解释:11 = 5 + 5 + 1

示例 2:

输入:coins = [2], amount = 3
输出:-1

示例 3:

输入:coins = [1], amount = 0
输出:0

示例 4:

输入:coins = [1], amount = 1
输出:1

示例 5:

输入:coins = [1], amount = 2
输出:2

5.2 算法思路

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.3 代码实现

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        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]&&dp[i-coins[j]]!=-1){
                    if(dp[i]==-1||dp[i]>dp[i-coins[j]]+1){
                        dp[i]=dp[i-coins[j]]+1;
                    }
                }
            }
        }
        return dp[amount];
    }
};

6.三角形最小路径和

6.1 题目描述

给定一个三角形 triangle ,找出自顶向下的最小路径和。

每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。

6.2 算法思路

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.3 代码实现

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        if(triangle.size()==0){
            return 0;
        }
        vector<vector<int>> dp;
        for(int i=0;i<triangle.size();i++){
            dp.push_back(vector<int>(i+1,0));
        }
        for(int i=0;i<triangle[triangle.size()-1].size();i++){
            dp[dp.size()-1][i]=triangle[triangle.size()-1][i];
        }
        for(int i=triangle.size()-2;i>=0;i--){
            for(int j=0;j<triangle[i].size();j++){
                dp[i][j]=getmin(dp[i+1][j],dp[i+1][j+1])+triangle[i][j];
            }
        }
        return dp[0][0];
    }
private:
    int getmin(int a,int b){
        return a<b?a:b;
    }
};

7.最长递增子序列

7.1 题目描述

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

7.2 算法思路

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

7.3 代码实现

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        if(nums.size()==0){
            return 0;
        }
        int result;
        vector<int> dp(nums.size(),0);
        dp[0]=1;
        int LIS=1;
        for(int i=1;i<nums.size();i++){
            dp[i]=1;
            for(int j=0;j<i;j++){
                if(nums[i]>nums[j]&&dp[j]+1>dp[i]){
                    dp[i]=dp[j]+1;
                }
            }
            if(LIS<dp[i]){
                LIS=dp[i];
            }
        }
        return LIS;
    }
};

8.最小路径和

8.1 题目描述

给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。

输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 13111 的总和最小。

示例 2:

输入:grid = [[1,2,3],[4,5,6]]
输出:12

8.2 代码实现

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        if(grid.size()==0){
            return 0;
        }
        vector<vector<int>> dp(grid.size(),vector<int>(grid[0].size(),0));
        dp[0][0]=grid[0][0];
        for(int i=1;i<dp[0].size();i++){
            dp[0][i]=grid[0][i]+dp[0][i-1];
        }
        for(int i=1;i<dp.size();i++){
            dp[i][0]=grid[i][0]+dp[i-1][0];
        }
        for(int i=1;i<dp.size();i++){
            for(int j=1;j<dp[0].size();j++){
                dp[i][j]=getmin(dp[i-1][j],dp[i][j-1])+grid[i][j];
            }
        }
        return dp[dp.size()-1][dp[0].size()-1];
    }
private:
    int getmin(int a,int b){
        return a<b?a:b;
    }
};

9.地下城游戏

9.1 题目描述

一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N
个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。

骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。

有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为
0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。

为了尽快到达公主,骑士决定每次只向右或向下移动一步。

编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。

例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。

9.2 算法思路

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.3 代码实现

class Solution {
public:
    int calculateMinimumHP(vector<vector<int>>& dungeon) {
        if(dungeon.size()==0){
            return 1;
        }
        int row=dungeon.size();
        int column=dungeon[0].size();
        vector<vector<int>> dp(row,vector<int>(column,0));
        dp[row-1][column-1]=getmax(1,1-dungeon[row-1][column-1]);
        
        for(int i=column-2;i>=0;i--){
            dp[row-1][i]=getmax(1,dp[row-1][i+1]-dungeon[row-1][i]);
        }
        for(int i=row-2;i>=0;i--){
            dp[i][column-1]=getmax(1,dp[i+1][column-1]-dungeon[i][column-1]);
        }
        for(int i=row-2;i>=0;i--){
            for(int j=column-2;j>=0;j--){
                dp[i][j]=getmin(getmax(1,dp[i+1][j]-dungeon[i][j]),getmax(1,dp[i][j+1]-dungeon[i][j]));
            }
        }
        return dp[0][0];
    }
private:
    int getmax(int a,int b){
        return a>b?a:b;
    }
    int getmin(int a,int b){
        return a<b?a:b;
    }
};
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值