线性dp

线性dp

1.最长上升子序列

给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:

输入: [10,9,2,5,3,7,101,18]

输出: 4

解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。

dp[i]

1

1

1

1

2

3

4

1


#include<iostream> 

#include<algorithm>

#define n 8

using namespace std;

int main(){

    int a[n];

    int dp[n];

    fill(dp,dp+n,1);

    for(int i=0;i<n;i++){

        cin>>a[i];

    }

    int maxn=1;

    for(int i=0;i<n-1;i++){

        for(int j=i+1;j<n;j++){

                 if(a[j]>a[i])

                    dp[j]=max(dp[j],dp[i]+1);

                 if(dp[j]>maxn) maxn=dp[j];

        }

    }

    cout<<maxn;

    return 0;

}

2.最长公共子序列

定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。

若这两个字符串没有公共子序列,则返回 0。

示例 1:

输入:text1 = "abcde", text2 = "ace"

输出:3 

解释:最长公共子序列是 "ace",它的长度为 3。

示例 2:

输入:text1 = "abc", text2 = "abc"

输出:3

解释:最长公共子序列是 "abc",它的长度为 3。

示例 3:

输入:text1 = "abc", text2 = "def"

输出:0

解释:两个字符串没有公共子序列,返回 0。



i         j

0

1 a

2 c

3 e

0

0

0

0

0

1 a

0

1

1

1

2 b

0

1

1

1

3 c

0

1

2

2

4 d

0

1

2

2

5 e

0

1

2

3

#include<iostream>
#include<vector>

using namespace std;

int main(){

         string text1,text2;

         cin>>text1>>text2;

         int m = text1.size();

    int n = text2.size();

    if(!m||!n)

    return 0;

    vector<vector<int> > dp(m+1,vector<int>(n+1,0));

    for(int i=1;i<=m;i++){

        for(int j=1;j<=n;j++){

            if(text1[i-1]==text2[j-1])

                dp[i][j]=dp[i-1][j-1]+1;

            else

                dp[i][j]=max(dp[i-1][j],dp[i][j-1]);

        }

     }

        cout<<dp[m][n];

}

2.0滚动数组

#include<iostream>

#include<vector>

using namespace std;

int main(){

         string text1,text2;

         cin>>text1>>text2;

         int m = text1.size();

    int n = text2.size();

    if(!m||!n)

    return 0;

    vector<vector<int> > dp2(2,vector<int>(n+1,0));//dp[2][n+1]滚动数组

    for(int i=1;i<=m;i++){

        for(int j=1;j<=n;j++){

            if(text1[i-1]==text2[j-1])

                dp2[i&1][j]=dp2[(i-1)&1][j-1]+1;

            else

                dp2[i&1][j]=max(dp2[(i-1)&1][j],dp2[i&1][j-1]);

        }

     }

        cout<<dp2[m&1][n];

}

3.三角形最短路径和

i

j

0

1

2

3

4

0

0

0

0

0

0

1

INF

2

INF

INF

INF

2

INF

5

6

INF

INF

3

INF

11

10

13

INF

4

INF

15

11

18

16

给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。

例如,给定三角形:

2

3 4

6 5 7

4 1 8 3

自顶向下的最小路径和为11(即,2+3+5+1= 11)。

#include<iostream>

#include<vector>

#include<limits>

#define n 4

using namespace std;

int main(){

         int a[n+1][n+1];

         for(int i=1;i<=n;i++){

                  for(int j=1;j<=i;j++){

                          cin>>a[i][j];

                  }

         }

         int ans=INT_MAX;

         vector<vector<int> > dp(n+1,vector<int>(n+1,INT_MAX));  

         for(int i=0;i<5;i++){

                  dp[0][i]=0;

         }

         for(int i=1;i<=n;i++){

                  for(int j=1;j<=i;j++){

                          dp[i][j]=min(dp[i-1][j],dp[i-1][j-1])+a[i][j];

                  }

         }

         for(int i=1;i<=n;i++){

                  ans=min(ans,dp[n][i]);

         }

         cout<<ans;

         return 0;

}

4.最大子序和

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

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],

输出: 6

解释:连续子数组[4,-1,2,1] 的和最大,为6。

i

0

1

2

3

4

5

6

7

8

9

dp[i]

0

-2

1

-2

4

3

5

6

1

5

#include<iostream>

#include<algorithm>

#include<climits>

#define n 9

using namespace std;

int main(){

         int a[n+1];

         int dp[n+1];

         fill(dp,dp+n+1,0);

         for(int i=1;i<=n;i++){

                  cin>>a[i];

         }

         int ans=INT_MIN;

         for(int i=1;i<=n;i++){

          dp[i]=max(dp[i-1]+a[i],a[i]);

          if(dp[i]>ans) ans=dp[i];

         }

         cout<<ans;

         return 0;

}

5

乘积最大子数组

示例 1:

输入: [2,3,-2,4]

输出: 6

解释:子数组 [2,3] 有最大乘积 6。

i

0

1

2

3

f[i]

2

6

-2

4

g[i]

2

3

-12

-48

示例 2:

{0,2}

i

0

1

f[i]

0

2

g[i]

0

0

示例 3:

{1,7,-2,-4}

i

0

1

2

3

f[i]

1

7

-2

56

g[i]

1

7

-14

-4

示例 4:

{1,2,-5,-2,-4,3}

i

0

1

2

3

4

5

f[i]

1

2

-5

20

8

24

g[i]

1

2

-10

-2

-80

-240

#include<iostream>

#include<vector>

using namespace std;

int main(){

         int n;

         cin>>n;

         int *num=new int[n];

         for(int i=0;i<n;i++){

                  cin>>num[i];

         }

    vector<int> f(n);

    vector<int> g(n);

    f[0]=num[0];//储存最大值

    g[0]=num[0];//储存最小值

         int ans = f[0];

    for (int i = 1; i < n; i++) {

        f[i] = max(f[i - 1] * num[i], num[i]);

        f[i] = max(g[i - 1] * num[i], f[i]);

        g[i] = min(f[i - 1] * num[i], num[i]);

        g[i] = min(g[i - 1] * num[i], g[i]);

        ans = max(ans, f[i]);

     }

         cout<<ans;

         return 0;

}

6.

鸡蛋掉落

你将获得K个鸡蛋,并可以使用一栋从1到N共有 N层楼的建筑。

每个蛋的功能都是一样的,如果一个蛋碎了,你就不能再把它掉下去。

你知道存在楼层F ,满足0 <= F <= N 任何从高于 F的楼层落下的鸡蛋都会碎,

从F楼层或比它低的楼层落下的鸡蛋都不会破。

每次移动,你可以取一个鸡蛋(如果你有完整的鸡蛋)并把它从任一楼层X扔下(满足1 <= X <= N)。

你的目标是确切地知道 F 的值是多少。

无论 F 的初始值如何,你确定 F 的值的最小移动次数是多少?

示例 1:

输入:K = 1, N = 2

输出:2

解释:

鸡蛋从 1 楼掉落。如果它碎了,我们肯定知道 F = 0 。

否则,鸡蛋从 2 楼掉落。如果它碎了,我们肯定知道 F = 1 。

如果它没碎,那么我们肯定知道 F = 2 。

因此,在最坏的情况下我们需要移动 2 次以确定 F 是多少。

示例 2:

输入:K = 2, N = 6

输出:3

示例 3:

输入:K = 3, N = 14

输出:4

提示:

1 <= K <= 100

1 <= N <= 10000

//超时 与历届试题中测试次数类似

#include<iostream>

#include<climits>

#include<vector>

using namespace std;

int main(){

         int k,n;//k个鸡蛋 n层楼

          while(cin>>k>>n){

          vector<vector<int> > dp(k+1,vector<int>(n+1,0));

          for(int i=1;i<=n;i++){

                 dp[1][i]=i;

          }//一个鸡蛋

          for(int i=1;i<=k;i++){

                 dp[i][1]=1;//无论几个鸡蛋1层只需扔一次

          }

          for(int i=2;i<=k;i++){

                 for(int j=1;j<=n;j++){

                         int ans=INT_MAX;

                         for(int k=1;k<=j;k++){

                         int _max=max(1+dp[i-1][k-1],1+dp[i][j-k]);//最坏情况下

                     ans=min(ans,_max);//最少移动距离

                         }      

                         dp[i][j]=ans;

                 }

          }

          cout<<dp[k][n]<<endl;

}

          return 0;

}

2.0

#include <iostream>

#include <vector>

#include <algorithm>

using namespace std;

class Solution {

public:

    int superEggDrop(int K, int N) {

        vector<int> dp(K + 1, 0);

        int m = 0;

        while (dp[K] < N) {//表示当能够测试的最大楼层数刚好是我们需要的楼层数N时,此时取得m的最小值。

            m++;

            for (int k = K; k > 0; --k) {

                dp[k] = dp[k - 1] + dp[k] + 1;//逆向遍历,不断更新dp[k],使得dp[k]取最大值(能够测试的最大楼层数)

            }

        }

        return m;

    }

};

 

int main()

{

    Solution A;

    cout << A.superEggDrop(3, 14);

 

    system("PAUSE");

    return 0;

}

ljm要加油
原文地址:https://www.cnblogs.com/ljmmm1/p/12739990.html