当前位置:   article > 正文

OJ——动态规划:最长公共子序列/最长上升子序列/最长回文子序列/最大子数组_最长公共上升子序列 loj

最长公共上升子序列 loj

动态规划题目练习列表:(都是经典,具体题目瞬间可搜)

1.最长公共子序列

2.最长上升子序列

3.最长回文子序列

4.最大子数组

5.矩阵链连乘

6.数塔问题

7.硬币问题

8.背包问题

经典五题,不如先做:https://blog.csdn.net/zmazon/article/details/8247015

这篇文章不错:https://blog.csdn.net/eagle_or_snail/article/details/50987044

知乎,关乎思想:https://www.zhihu.com/question/23995189

 

1.最长公共子序列(POJ1458)

  1. #include<iostream>
  2. #include<vector>
  3. #include<string>
  4. #include<algorithm>
  5. using namespace std;
  6. int main(){
  7. string str1,str2;
  8. while(cin>>str1>>str2){
  9. vector<vector<int> >dp(str1.length()+1,vector<int>(str2.length()+1,0)); //创建动态规划数组并初始化
  10. for (int i=1; i < str2.length() + 1; i++) { //填表
  11. for (int j=1; j < str1.length() + 1; j++) {
  12. if (str2[i-1] == str1[j-1]) { //I mad a mistake here.
  13. dp[i][j] = dp[i - 1][j - 1]+1;
  14. }
  15. else {
  16. dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
  17. }
  18. }
  19. }
  20. /*输出测试
  21. for(int i=0;i<=str1.length();i++){
  22. for(int j=0;j<=str2.length();j++){
  23. cout<<dp[i][j]<<" ";
  24. }
  25. cout<<endl;
  26. }*/
  27. cout<<dp[str1.length()][str2.length()]<<endl; //输出结果
  28. }
  29. return 0;
  30. }

纠错:

  • 动态规划的数组多一行和多一列的时候要注意和输入数据匹配一下。

心得:动态规划的一类题,只要会填表格就可以翻译出代码,真的!!!那么主要问题就是“表格”。

转移方程

        如果dp数组行和列对应的内容相等,则为斜左上方的内容+1;

        如果不相等,则为上方或者左方较大的一个(如果相等取上方,代码);

输入样例

abcfbc         abfcab

样例表格:(dp过程)

 

 

a

b

f

c

a

b

 

0

0

0

0

0

0

0

a

0

(斜)1

->1

->1

->1

(斜)1

->1

b

0

(上)1

(斜)2

->2

->2

->2

->2

c

0

(上)1

(上)2

(上)2

(斜)3

->3

->3

f

0

(上)1

(上)2

(斜)3

->3

(上)3

(上)3

b

0

(上)1

(斜)2

(上)3

(上)3

(上)3

(斜)4

c

0

(上)1

(上)2

(上)3

(斜)4

->4

(上)4

 

表格画法

                行和列分别是两个字符串的长度+1;多出来的一行和一列是用来初始化为0的;

                一行一行从上往下,从左往右填。


2.最长上升子序列(百练2757)

  1. #include<iostream>
  2. #include<vector>
  3. #include<algorithm>
  4. using namespace std;
  5. int main_lis(){ //需要修改主函数
  6. int len;
  7. while(cin>>len){
  8. //数据的存储与输入
  9. vector<int>v(len);
  10. for(int i=0;i<len;i++){
  11. cin>>v[i];
  12. }
  13. //dp
  14. vector<int>dp(len,1);
  15. for(int i=1;i<len;i++){
  16. for(int j=0;j<i;j++){
  17. if(v[i]>v[j]){ // I made a mistake here.
  18. dp[i]=max(dp[j]+1,dp[i]); //!! I made a mistake here
  19. }
  20. }
  21. }
  22. /*测试输出
  23. for(int i=0;i<len;i++){
  24. cout<<dp[i]<<" ";
  25. }
  26. cout<<endl;*/
  27. //结果 !! I forgot this part ever.
  28. int result=0;
  29. for(int i=0;i<len;i++){
  30. if(result<dp[i])result=dp[i];
  31. }
  32. cout<<result;
  33. }
  34. return 0;
  35. }

 (做这道题的时候,自己有个很愚蠢的点,在处理个别样例的时候,判断过它后就直接输出结果了,甚至没有让该输入的样例输入完,这肯定会影响后续的结果)

纠错:

  • 首先,dp更新的条件就错了,是输入数据自己和自己比。
  • 其次,更新dp的式子是选最大的。因为j的那一层循环里面是有大有小的,要保证是最大的那一个。
  • 最后,忘了结果。前面的算法是把每一个当作最后一个的时候的最长上升子序列。那么,所有的当然要在所有的里面找。

想法:这其实不是一个“想要整体,就从局部的过程”。因为最后的解决还要靠寻找最大值。

           每一个数,都能影响前面的整条,所以——先针对每一个数,在前面的里面找到最长上升子序列。

           最后,找出最大的。

样例

1 7 3 5 9 4 8

dp过程:

前1个数:1

前2个数:27

前3个数:13

前4个数:135

前5个数:1359

前6个数:134

前7个数:1348


3.最长回文子序列(Leetcode:5)

  1. #include<iostream>
  2. #include<string>
  3. #include<vector>
  4. #include<algorithm>
  5. using namespace std;
  6. class Solution {
  7. public:
  8. string longestPalindrome(string s) {
  9. int start=0, plus=0;
  10. if(s.length()==0){ // cause run time error, if forget it
  11. return "";
  12. }
  13. //dp & init
  14. vector<vector<int> >dp(s.length(), vector<int>(s.length(), 0));
  15. for (int i = 0; i < s.length();i++) {
  16. dp[i][i] = 1;
  17. }
  18. for (int i = 0; i < s.length() - 1; i++) {
  19. if (s[i] == s[i + 1]) {
  20. dp[i][i + 1] = 1;
  21. start = i; // cause WA, if forget it
  22. plus = 1;
  23. }
  24. }
  25. //dp
  26. for (int i = 2; i < s.length(); i++) {
  27. for (int j = 0; j+i < s.length(); j++) { // I made a mistake here // remember "j+i"
  28. if (s[j] == s[j + i]) {
  29. dp[j][j + i] =dp[j + 1][j + i - 1];
  30. if (dp[j + 1][j + i - 1] == 1&&plus<=i) {
  31. start = j;
  32. plus = i;
  33. }
  34. else {
  35. dp[j][j + i] = 0;
  36. }
  37. }
  38. }
  39. }
  40. return s.substr(start,plus+1);
  41. //cout << dp[0][input.length() - 1] << endl;
  42. }
  43. };

纠错:

  • 数组越界:dp的上三角填法,第二个循环的约束是“j+i<input.leng()”而不是“j<input.length()”
  • 数组越界:题目的输入是字符串,忘记考虑特殊样例“” ,访问不到自然数组越界。
  • WA:在输出处理的过程比较复杂的时候,只考虑了通常样例,没有考虑特殊样例。

心得:dp的输入如果是一个串,问串里面可能存在的情况,就填dp数组的上三角。

转移方程

dp[j][j+i]=dp[j+1][j+i-1](if str[j]==str[j+i])

dp[j][j+i]=0(if str[j]\neq str[j+i])

4.最大子数组(LeetCode:53)

  1. #include<iostream>
  2. #include<vector>
  3. #include<algorithm>
  4. using namespace std;
  5. class Solution {
  6. public:
  7. int maxSubArray(vector<int>& nums) {
  8. vector<int>dp(nums.size());
  9. int max_num=0;
  10. //init
  11. dp[0] = nums[0];
  12. max_num = nums[0];
  13. //dp
  14. for (int i = 1; i < nums.size(); i++) {
  15. dp[i] = max(dp[i - 1] + nums[i], nums[i]); //name error
  16. if (max_num < dp[i]) {
  17. max_num = dp[i];
  18. }
  19. }
  20. //cout << max_num << endl;
  21. return max_num;
  22. }
  23. };

心得:dp问题的数组也许无法记录最终的结果,常常要在过程中记录最值以表示结果。

转移方程max(dp[i])=max(dp[i-1]+input[i],input[i])


5.动态规划0-1背包专题:(建设中。。。)

     

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/981707
推荐阅读
相关标签
  

闽ICP备14008679号