开宗明义:本系列基于小象学院林沐老师课程《面试算法 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;
}
效果图: