Leetcode学习之动态规划(1)

本博客基于小象学院课程,记录LeetCode刷题中动态规划相关内容。介绍了动态规划概念,通过爬楼梯、打家劫舍、最大字段和、找零钱等LeetCode题目,分析问题并给出测试代码,帮助理解动态规划在实际算法中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

开宗明义:本系列基于小象学院林沐老师课程《面试算法 LeetCode 刷题班》,刷题小白,旨在理解和交流,重在记录,望各位大牛指点!


Leetcode学习之动态规划(1)



0、动态规划

动态规划:利用各个阶段之间的关系逐个求解,最终得到全局最优解。设计时,需要确定原问题与子问题、动态规划状态、边界状态结值、状态转移方程等关键因素。


1、爬楼梯 LeetCode 70.

题目来源 L e e t C o d e   70.   C l i m b i n g   S t a i r s LeetCode \ 70. \ Climbing \ Stairs LeetCode 70. Climbing Stairs
描述在爬楼梯时,每次可选择向上走1阶台阶或者2阶台阶,问有n阶楼梯有多少种上楼方式
在这里插入图片描述
分析典型的我们可以使用暴力搜索-回溯法
测试代码:

#include <stdio.h>
#include <iostream>

class Solution {
public:
	int climbStairs(int n) {
		if (n == 1 || n == 2) {
			return n;
		}
		return climbStairs(n - 1) + climbStairs(n - 2);
	}
};

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

效果图
在这里插入图片描述
再分析:
在这里插入图片描述
算法思路
在这里插入图片描述
测试代码:

#include <stdio.h>
#include <iostream>
#include <vector>
using namespace std;

class Solution {
public:
	int climbStairs(int n) {
		vector<int> dp(n + 3, 0);	//这句话表示 创建一个 int 类型n个+3元素,且值均为0的vecotr容器dp。
		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));
	system("pause");
	return 0;
}

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


以上例子我们可以得出动态规划原理:

在这里插入图片描述


2、打家劫舍 LeetCode 198.

题目来源 L e e t C o d e   198.   H o u s e   R o b b e r LeetCode \ 198. \ House \ Robber LeetCode 198. House Robber
描述在一条直线上,有n个房屋,每个房屋有数量不等的财宝,有一个盗贼希望从房屋中盗取财宝,由于房屋中有报警器,如果同时从相邻的两个房屋中盗取财宝就会触发报警器。问不触发报警器的前提下,最多可获取多少财宝
在这里插入图片描述
思考
在这里插入图片描述
分析
在这里插入图片描述
在这里插入图片描述
测试代码:

#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

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

		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 - 1], dp[i - 2] + nums[i]);
		}

		return dp[nums.size() - 1];
	}
};

int main() {
	Solution solve;
	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));
	system("pause");
	return 0;
}

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


3、最大字段和 LeetCode 53.

题目来源 L e e t C o d e   53.   M a x m u m   S u b a r r a y LeetCode \ 53. \ Maxmum \ Subarray LeetCode 53. Maxmum Subarray
描述给定一个数组,求这个数组的连续子数组中,最大的那一段的和

在这里插入图片描述
思考
在这里插入图片描述
分析
在这里插入图片描述
在这里插入图片描述

测试代码:

#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

class Solution {
public:
	int maxSubArray(vector<int>& nums) {
		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] = max(dp[i - 1] + nums[i],nums[i]);	//这边注意调用STL里面的max函数的目的

			if (max_res < dp[i]) {
				max_res = dp[i];
			}
		}
		return max_res;
	}
};

int main() {
	Solution solve;
	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));
	system("pause");
	return 0;
}

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


4、找零钱 LeetCode 322.

题目来源 L e e t C o d e   322.   C o i n   C h a n g e LeetCode \ 322. \ Coin \ Change LeetCode 322. Coin Change
描述已知不同面值的钞票,求如何用最少数量的钞票组成某个金额,求可以使用的最少钞票数量。如果任意数量的钞票都无法组成该金额,则返回-1
在这里插入图片描述
思考
在这里插入图片描述
分析
在这里插入图片描述
在这里插入图片描述

测试代码:

#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

class Solution {
public:
	int coinChange(vector<int> &coins, int amount) {	//这边amount是金钱面值
		vector<int> dp;

		//初始化dp数组
		for (int i = 0; i <= amount; i++) {
			dp.push_back(-1);	//最初所有金额的最优解均为-1(不可达到)
		}

		dp[0] = 0;	//金额0的最优解0	//递推

		for (int i = 1; i <= amount; i++) {		//循环各个面值,找到dp[i]的最优解
			for (int j = 0; j < coins.size(); j++) {
				//在计算dp[i]的时候,dp[0],dp[1],....dp[i-1]都是已知的
				if (i - coins[j] >= 0 && dp[i - coins[j]] != -1) {	//金钱i大一金钱备选里面的coins[j]  并且 i - coins[j]  有最优解
					if (dp[i] == -1 || dp[i] > dp[i - coins[j]] + 1) {  //金钱i没有最优解  或者  当前金钱i的最优解的个数大于相邻得的
						dp[i] = dp[i - coins[j]] + 1;
					}
				}
			}
		}
		return dp[amount];
	}
};

int main() {
	Solution solve;
	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", 5, solve.coinChange(coins, 5));
	//}
	system("pause");
	return 0;
}

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值