力扣 题目10-正则表达式匹配 上--几个动态规划思想例题的详解
-
力扣原题目
-
刚才有个朋友问我发生什么事了,我说怎么回事,给我发了几张截图。
我一看!嗷!原来是昨天,有两个年轻人。
- 三十多岁,一个体重,九十多公斤,一个体重八十多公斤。
- 他们用正则表达式函数直接解决了这道题
- 这两个年轻人不讲武德,来骗!来偷袭,力扣。这好吗?这不好!
- 我劝!这位年轻人好自为之,好好反思,以后不要再犯这样的聪明,小聪明,啊,呃…程序员要以和为贵,要讲武德,不要搞窝里斗。
-
不开玩笑了啊这题暴力肯定是可以解的 但是太麻烦 我一看题解好家伙 动态规划
-
一年前学的早忘记了 我赶忙去复习了一波动态规划 然后做了几道题写一下过程
-
至于上面的第10题的解答等下篇再说
-
题目一
如果一个奇葩国家的钞票面额分别是1、5、11,我们需要凑出15 并且用的钱张数最小--出自 https://www.zhihu.com/question/23995189(动态规划可以看这个学习一下)
-
题解
-
先写状态转移方程 n是剩下的钱数 f(n)就是张数
-
f(n)=min(f(n-1),f(n-5),f(n-11))+1;
-
拿15举例 f(15)=min(f(14),f(10),f(4))+1 就是说我们想要找到15最少张数就要找到 14/10/4中最少的那张然后 14/10/4也要和15一样分别去分 直到为1的时候停止
-
然后我们可以写成这样的代码 cost = min(cost, f[i - 1] + 1) cost是一个很大的值 而f[i - 1] + 1是在上一次拿了一张一元的张数+1 5/11同理 然后从1往11判断得到最小(用一个数组全部存起来 具体看代码)
-
代码
-
#include<iostream> #include<string> using namespace std; int main() { int n,i,cost; int f[105]; cin >> n; f[0] = 0; for (i = 1; i <=n; i++) { cost = INT_MAX; if (i - 1 >= 0) { cost = min(cost, f[i - 1] + 1) ;} if (i - 5 >= 0) { cost = min(cost, f[i - 5] + 1); } if (i - 11 >= 0) { cost = min(cost, f[i - 11] + 1); } f[i] = cost; cout << "f[" << i << "]=" << f[i] << endl; } }
-
题目二
-
最长上升子序列(LIS)问题:给定长度为n的序列a,从a中抽取出一个子序列,这个子序列需要单调递增。问最长的上升子序列(LIS)的长度。
e.g. 1,5,3,4,6,9,7,8的LIS为1,3,4,6,7,8,长度为6。 -
题解
-
1.从小试大
-
我们这里先用前几个数观察 f(1)=1 f(2)=2 f(3)=2 f(4)=3 即f(4)=f(3)+1;f(3)=f(1)+1; 即前面最大的+1
-
f(n)=max(f(前面))+1;
-
这里使用双循环
-
代码
-
#include<iostream> #include<string> using namespace std; int main() { int a[8] = {1,5,3,4,6,9,7,8}; int b[8] = {1}; for (int i = 0; i < 8; i++) { for (int j = 0; j < i; j++) { if(a[j]<a[i]){ b[i] = max(b[i], b[j] + 1); } } cout << "b["<<i<<"]=" << b[i]<<endl; } cout << b[7] << endl; }
-
题目三

-
题解
-
找到前面的最大的然后加上本身的数 和本身的数进行比较即可
-
lent[0] = nums[0];
-
lent[i] = max(lent[i - 1]+nums[i], nums[i]);
-
代码
-
#include<iostream> #include<string> using namespace std; int main() { int nums[9] = { -2, 1, -3, 4, -1, 2, 1, -5, 4 }; int lent[9]; int max1 = 0; lent[0] = nums[0]; for (int i = 1; i < 9; i++) { lent[i] = max(lent[i - 1]+nums[i], nums[i]); cout << "lent[" << i << "]=" << lent[i] << endl; if (lent[i] > max1) { max1 = lent[i]; } } cout << max1 << endl; }
-
题目四

-
题解
-
这题考虑到不能相邻 所以 上一个房间与本房间挨着所以只需要上个房间的最大值 但 上上一个房间不挨着本房间所以可以加上本房间的金额即
-
b[i] = max(b[i-1], b[i-2] + a[i]);
-
代码
-
#include<iostream> #include<string> using namespace std; int main() { int a[5] = {1,25,10,22,55}; int b[5]; for (int i = 0; i < 5; i++) { if (i==0) { b[i] = a[i]; } else if(i==1) { b[i] = max(a[0], a[1]); } else if (i > 1) { b[i] = max(b[i-1], b[i-2] + a[i]); } cout << b[i] << endl; } }
-
题目五

-
题解
-
找几个前面的例子一试 发现了 当N为偶数 爱丽丝就会赢 所以这题就做完了(不是)
-
既然是动态规划 我们就来看一下这题怎么做
-
以30为例 30能赢 那么他的因数中有能赢的 那么这个因数既然能赢 那么这个因数的因数也有可以胜利的
-
就是这样我们推到2就会发现 2的倍数就是赢
-
代码
-
#include<iostream> #include<string> using namespace std; int main() { bool dp[31]; dp[1] = false; for (int i = 2; i <= 30; i++) { dp[i] = false; for (int j = 1; j < i; j++) { if (i % j == 0 && dp[i - j] == false) { dp[i] = true; break; } } } cout << dp[30] << endl; }
-
心得
动态规划是一种特殊的思想 可以剩下很多内存并且减少时间复杂度 但是不容易想到 需要多加练习
-
说实话我在写题解的时候并不知道该怎么写 因为很多东西脑子里有但是不知道怎么表达 只能写一些重点上去了(反正也是我一个人看)

浙公网安备 33010602011771号