zoukankan      html  css  js  c++  java
  • 算法复习:动态规划

    一、动归引入

    leetcode 70. 爬楼梯

    class Solution {
    public:
        int climbStairs(int n) {
            map<int,int>donser;
            for(int i=1;i<=n;i++)
            {
                if(i==0||i==1||i==2)
                    donser[i]=i;
                else
                    donser[i]=donser[i-1]+donser[i-2];
            }
            return donser[n];
        }
    };
    ------------------------------------------------------------------------
    class Solution {
    public:
        int climbStairs(int n) {
            if(n<=3)
                return n;
            int now=3,last_1=2,last_2=1;
            for(int i=3;i<=n;i++)
            {
                now=last_1+last_2;
                last_2=last_1;
                last_1=now;
            }
            return now;
        }
    };
    leetcode 70

     

    leetcode 198. 打家劫舍

    前一个位置取了值,下一个位置就不能再取,寻找最大的组合。dp[i]表示抢了i处以后的最大总金额,dp[i]=maxl+nums[i]   (maxl=(maxl>dp[0->i-1]?maxl:dp[0->i-1]))

    class Solution {
    public:
        int rob(vector<int>& nums) {
            if(nums.size()==0)
                return 0;
            if(nums.size()<2)
                return nums[0];
            vector<int>dp(nums.size(),0);
            dp[0]=nums[0];
            dp[1]=nums[1];
            for(int i=2;i<nums.size();i++)
            {
                int maxl=0;
                for(int j=0;j<i-1;j++)
                    maxl=(maxl>dp[j]?maxl:dp[j]);
                dp[i]=maxl+nums[i];
            }
            return (dp[nums.size()-1]>dp[nums.size()-2]?dp[nums.size()-1]:dp[nums.size()-2]);
        }
    };
    leetcode 198

    leetcode 213. 打家劫舍 II

    在上一题基础上做了首尾相连,也就是头和尾只能选一个。改进方法就是分别查找不含头的最大价值和不含尾的最大价值,输出二者中的最大值

    #include<map>
    class Solution {
    public:
        int deal(vector<int>& nums)
        {
            vector<int>dp(nums.size(),0);
            dp[0]=nums[0];
            dp[1]=nums[1];
            for(int i=2;i<nums.size();i++)
            {
                int maxl=0;
                for(int j=0;j<i-1;j++)
                    maxl=(maxl>dp[j]?maxl:dp[j]);
                dp[i]=maxl+nums[i];
            }
            return (dp[nums.size()-1]>dp[nums.size()-2]?dp[nums.size()-1]:dp[nums.size()-2]);
        }
        int rob(vector<int>& nums) {
            if(nums.size()==0)
                return 0;
            if(nums.size()==1)
                return nums[0];
            if(nums.size()==2)
                return max(nums[0],nums[1]);
            vector<int> num1,num2;
            for(int i=0;i<nums.size();i++)
            {
                if(i==0)
                {
                    num2.push_back(nums[i]);
                    continue;
                }
                if(i==nums.size()-1)
                {
                    num1.push_back(nums[i]);
                    continue;
                }
                num1.push_back(nums[i]);
                num2.push_back(nums[i]);
            }
            return max(deal(num1),deal(num2));
        }
    };
    leetcode 213

     面试题60. n个骰子的点数

     递推 f(n,x)=f(n-1,x-1)+f(n-1,x-2)+f(n-1,x-3)+f(n-1,x-4)+f(n-1,x-5)+f(n-1,x-6)

    class Solution {
    public:
        int f(int n,int x,vector<vector<int> >&dp)
        {
            if(x<=0||n<=0)
                return 0;
            if(dp[n][x]!=0)
                return dp[n][x];
            int sum=0;
            for(int i=1;i<=6;i++)
            {
                sum+=f(n-1,x-i,dp);
            }
            dp[n][x]=sum;
            return sum;
        }
        vector<double> twoSum(int n) {
            vector<vector<int> >dp(n+1,vector<int>(6*n+1,0));
            vector<double>result;
            for(int i=1;i<=6;i++)
                dp[1][i]=1;
            int sum=0,ll=0;
            for(int x=n;x<=int((n*6+n)/2);x++)
            {
                ll=f(n,x,dp);
                sum+=ll;
                result.push_back(ll);
            }
            int size=result.size();
            sum*=2;
            if(n%2==0)
                sum-=ll;
            for(int i=size-1;i>=0;i--)
            {
                if(n%2==0&&i==size-1)
                {
                    result[i]=result[i]/sum;
                    continue;
                }
                result[i]=result[i]/sum;
                result.push_back(result[i]);
            }
            return result;
        }
    };
    View Code

    72. 编辑距离

    递推三个状态:

    替换:到dp[i-1][j-1]到k步,那么word1[i-1]==word2[j-1]时dp[i][j]要k步,≠时k+1步

    删除:到dp[i-1][j]要k步,那么到dp[i][j]要k+1步

    添加:到dp[i][j-1]要k步,那么到dp[i][j]要k+1步

    const int inf = 0x3f3f3f3f;
    class Solution {
    public:
        int minDistance(string word1, string word2) {
            int a=word1.size();
            int b=word2.size();
            if(a==0||b==0)
                return a+b;
            vector<vector<int> >dp(a+1,vector<int>(b+1,inf));
            for(int i=0;i<=a;i++)
                dp[i][0]=i;
            for(int j=0;j<=b;j++)
                dp[0][j]=j;
            for(int i=1;i<=a;i++)
            {
                for(int j=1;j<=b;j++)
                {
                    if(word1[i-1]==word2[j-1])
                        dp[i][j]=min(dp[i-1][j-1],dp[i][j]);
                    else
                        dp[i][j]=min(dp[i-1][j-1]+1,dp[i][j]);
                    dp[i][j]=min(dp[i-1][j]+1,dp[i][j]);
                    dp[i][j]=min(dp[i][j-1]+1,dp[i][j]);
                }
            }
            /*for(int i=1;i<=a;i++)
            {
                for(int j=1;j<=b;j++)
                {
                    cout<<dp[i][j]<<" ";
                }
                cout<<endl;
            }*/
            return dp[a][b];
        }
    
    };
    leetcode 72 

    5. 最长回文子串

     设dp[i][j]==1表示从i到j是一个回文串

    dp[i][j]=1的条件是dp[i+1][j-1]==1且s[i]==s[j]

    特殊情况*bb*这样子,判断一下j-i是不是==1,是的话dp[i][j]=1

    class Solution {
    public:
        string longestPalindrome(string s) {
            if(s.size()<=1)
                return s;
            int size=s.size();
            int max_len=1;
            int start=0;
            vector<vector<int> >dp(size,vector<int>(size,0));
            for(int i=0;i<size;i++)//对角线置1
                dp[i][i]=1;
            for(int i=size-1;i>=0;i--)
            {
                for(int j=i+1;j<size;j++)
                {
                    if(s[i]==s[j])
                    {
                        if(j-i==1)//处理bb情况
                        {
                            dp[i][j]=1;
                            max_len=max(max_len,j-i+1);
                            if(max_len==j-i+1)
                                start=i;
                        }
                        else if(dp[i+1][j-1]==1)
                        {
                            dp[i][j]=dp[i+1][j-1];
                            max_len=max(max_len,j-i+1);
                            if(max_len==j-i+1)
                                start=i;
                        }
                            
                    }
                }
            }
            return s.substr(start,max_len);
        }
    };
    leetcode 5

    二、0-1背包

    01背包经典模板

    01背包列出了所有可用的元素,每个元素可用一次或者不用。

    n是n件物品,m是背包最大容量,v[]存每件物品的价值,w[]存每件物品的体积,

    f[]维护一个一维数组:f(m) 当前背包容量为m的情况下取得的价值为f(m)

    状态转移方程:f(m)=max( f(m) , f(m-w[i])+v[i] )   表示不选当前物品 或者 选择当前物品

    容量从大到小遍历,那么到最后的f[m]取决的结果是基于上一物品选择

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1010;
    int f[N];
    int v[N],w[N];
    int n,m;
    int main()
    {
        cin>>n>>m;
        for(int i=0;i<n;i++)
            cin>>v[i]>>w[i];
        for(int i=0;i<n;i++)
            for(int j=m;j>=w[i];j--)
                f[j]=max(f[j],f[j-w[i]]+v[i]);
        cout<<f[m]<<endl;
    }

     leetcode 416. 分割等和子集

    class Solution {
    public:
        bool canPartition(vector<int>& nums) 
        {
            int sum=0;
            vector<int>v,w,f;//v存价值 w存体积 f[i]=j表示容积为i时价值为j
            for(int i=0;i<nums.size();i++)
            {
                sum+=nums[i];
                v.push_back(nums[i]);
                w.push_back(nums[i]);
            }
            if(sum%2==1)
                return false;
            sum/=2;//背包容量为sum
            for(int i=0;i<=sum;i++)//初始化f
                f.push_back(0);
            for(int i=0;i<nums.size();i++)
            {
                for(int j=sum;j>=w[i];j--)
                {
                    f[j]=max(f[j],f[j-w[i]]+v[i]);
                }
            }
            if(f[sum]==sum)
                return true;
            return false;
        }
    };
    leetcode 416

     leetcode 474. 一和零

    本题是01背包的扩展,二维费用背包,有两个费用指标,多加一层内循环即可

    class Solution {
    public:
        int findMaxForm(vector<string>& strs, int m, int n) 
        {
            vector<int>goods_0;
            vector<int>goods_1;
            vector<vector<int>>dp(m+1,vector<int>(n+1,0));
            for(int i=0;i<strs.size();i++)//创建输入
            {
                string tmp=strs[i];
                int x=0,y=0;
                for(int j=0;j<tmp.size();j++)
                {
                    if(tmp[j]=='0')
                        x++;
                    if(tmp[j]=='1')
                        y++;
                }
                goods_0.push_back(x);
                goods_1.push_back(y);
            }
            for(int i=0;i<strs.size();i++)
                for(int j=m;j>=goods_0[i];j--)
                    for(int k=n;k>=goods_1[i];k--)
                        dp[j][k]=max(dp[j][k],dp[j-goods_0[i]][k-goods_1[i]]+1);
            return dp[m][n];
        }
    };
    leetcode 474

     leetcode 494. 目标和

    01背包的变体,即:每一个数字都要用,每一个数字或是加或是减,下标需要平移到正数

    dp[i][j]=A表示截止到第i+1个数,这i+1个数的数字和为j时的方案数为A个。  状态转移方程:dp[i][j]=dp[i-1][j-nums[i]]+dp[i-1][j+nums[i]]

    class Solution {
    public:
        int findTargetSumWays(vector<int>& nums, int S) {
            int count=0;
            for(int i=0;i<nums.size();i++)
                count+=nums[i];
            if(count<S)
                return 0;
            vector<vector<int>>dp(nums.size()+1,vector<int>((count+2)*2,0));
            dp[0][nums[0]*(-1)+count]+=1;
            dp[0][nums[0]+count]+=1;
            for(int i=1;i<nums.size();i++)
            {
                for(int j=0;j<=count*2;j++)
                {
                    int x=(j-nums[i])>0?(j-nums[i]):0;
                    int y=(j+nums[i])<=count*2?(j+nums[i]):0;
                    dp[i][j]=dp[i-1][x]+dp[i-1][y];
                }
            }
            return dp[nums.size()-1][abs(S)+count];
        }
    };
    leetcode 494

    三、最长公共子序列

    leetcode 1143. 最长公共子序列

    分析,两串匹配串放在一起组成一个二维表,逐层更新表内内容,直到最后。

    状态转移方程:A==B时 dp[i][j]=dp[i-1][j-1]+1

                              A!=B时 dp[i][j]=max( dp[i-1][j] , dp[i][j-1] )

    class Solution {
    public:
        int longestCommonSubsequence(string text1, string text2) {
            vector<vector<int>> dp(text2.size()+1,vector<int>(text1.size()+1,0));//初始化
            for(int i=1;i<=text2.size();i++)
            {
                char A=text2[i-1];
                for(int j=1;j<=text1.size();j++)
                {
                    char B=text1[j-1];
                    if(A==B)
                        dp[i][j]=dp[i-1][j-1]+1;
                    else
                        dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
                }
            }
            return dp[text2.size()][text1.size()];
        }
    };
    leetcode 1143

     优化:将二维数组改成只有两行的数组节省空间,原理:原来解法的更新只看两行继续存着意义不大,因此只留两行

    class Solution {
    public:
        int longestCommonSubsequence(string text1, string text2) {
            vector<vector<int>> dp(2,vector<int>(text1.size()+1,0));
            for(int i=1;i<=text2.size();i++)
            {
                char A=text2[i-1];
                for(int j=1;j<=text1.size();j++)
                {
                    char B=text1[j-1];
                    if(A==B)
                        dp[i&1][j]=dp[(i-1)&1][j-1]+1;
                    else
                        dp[i&1][j]=max(dp[(i-1)&1][j],dp[i&1][j-1]);
                }
            }
            return dp[text2.size()&1][text1.size()];
        }
    };
    leetcode 1143

    四、最长上升子序列

    leetcode 300. 最长上升子序列

    分析:在一个数字串中寻找最长上升,用一个一维dp。dp[i]表示截至当前i位置最长的上升序列

    状态转移方程:dp[i]=max(dp[j]+1 j: 0->i-1)

    class Solution {
    public:
        int maxl(vector<int>&dp)
        {
            int max=0;
            for(int i=0;i<dp.size();i++)
            {
                if(dp[i]>max)
                    max=dp[i];
            }
            return max;
        }
    
        int lengthOfLIS(vector<int>& nums) 
        {
            vector<int>dp(nums.size(),0);
            for(int i=0;i<nums.size();i++)
            {
                int lable=0;
                if(i==0)
                {
                    dp[i]=1;
                    continue;
                }
                for(int j=i-1;j>=0;j--)
                {
                    if(nums[j]<nums[i]&&dp[i]<dp[j]+1)
                    {
                        dp[i]=dp[j]+1;
                        lable=1;
                    }
                }
                if(lable==0)
                    dp[i]=1;   
            }      
            return maxl(dp);
        }
    };
    
    ---------------------------------------------------------------
    优化 dp初值付1这样就不要lable了
    
    class Solution {
    public:
        int maxl(vector<int>&dp)
        {
            int max=0;
            for(int i=0;i<dp.size();i++)
            {
                if(dp[i]>max)
                    max=dp[i];
            }
            return max;
        }
        int lengthOfLIS(vector<int>& nums) 
        {
            vector<int>dp(nums.size(),1);
            for(int i=0;i<nums.size();i++)
            {
                for(int j=i-1;j>=0;j--)
                {
                    if(nums[j]<nums[i]&&dp[i]<dp[j]+1)
                        dp[i]=dp[j]+1;
                }  
            }      
            return maxl(dp);
        }
    };
    leetcode 300

    五、完全背包

    完全背包相比于01背包,每件物品可以取无限多次,完全背包的核心代码:(简记和01背包的不同之处在于第二层循环)

    dp[m]表示的就是当容量<=m时的最优解是多少,可能背包并没有装满。如果需要恰好容量==m时的最优解是多少,初始化dp[0]=0 其他的初始化为-∞

    dp[j]表示容量最大为j时所能存放的最大价值。  状态转移方程:dp[j]=max(dp[j],dp[j-v[i]]+w[i]) 

    for(int i=0;i<N;i++)
        for(int j=v[i];j<=m;j++)
            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);

    leetcode 322. 零钱兑换

    这道题不是纯的完全背包,因为恰好装满背包的方法有无数种,而本体需要的结果是所有结果中所用数量最少的那一个解

    dp[j]表示容量最大为j时所用的最少硬币数量。 状态转移方程:dp[j]=min(dp[j],dp[j-w[i]]+1)

    #define MAX 999999
    int minl(int a,int b)
    {
        return (a>b?b:a);
    }
    class Solution {
    public:
        int coinChange(vector<int>& coins, int amount) 
        {
            vector<int>dp(amount+1,MAX);
            dp[0]=0;
            for(int i=0;i<coins.size();i++)
            {
                for(int j=coins[i];j<=amount;j++)
                {
                    dp[j]=minl(dp[j],dp[j-coins[i]]+1);
                }
            }
            return (dp[amount]==MAX?-1:dp[amount]);
        }
    };
    leetcode 322

    leetcode 518. 零钱兑换 II

    和上一题的不同之处在于,本题要求解的是所有装满背包的组合数目

    dp[j]表示装满容量j时的可能的组合数目。 状态转移方程:dp[j]=dp[j]+dp[j-w[i]]

    class Solution {
    public:
        int change(int amount, vector<int>& coins)
        {
            vector<int>dp(amount+1,0);
            dp[0]=1;
            for(int i=0;i<coins.size();i++)
            {
                for(int j=coins[i];j<=amount;j++)
                {
                    dp[j]=dp[j]+dp[j-coins[i]];
                }
            }
            return dp[amount];
        }
    };
    leetcode 518

    六、多重背包

    多重背包可以看作是01背包的扩展,每一件物品最多有固定个,简单的来理解就是内层多加一个循环遍历物品数量

    dp[j]表示容量为j时物品最大的价值。 状态转移方程:dp[j]=max(dp[j] , dp[j-w[i]]+v[i] , dp[j-2*w[i]]+2*v[i] , ......,dp[j-k*w[i]]+k*v[i] ) 设有最多k个物品i

    for(int i=0;i<n;i++)
            for(int j=m;j>=v[i];j--)
                    for(int k=1;k<=s&&j-k*w[i]>=0;k++)
                            f[j]=max(f[j],f[j-k*w[i]]+k*v[i]);

     多重背包的二进制优化

    原理:物品A(价值v重量w)有7个,如果全都列举出来就是{(0*v,0*w),(1*v,1*w),......,(7*v,7*w)},这样再当作01背包来做时间复杂度太高

    改进:由于2^0=1,2^1=2,2^2=4 ,1 2 4 可以组成0~7的所有情况,所以只需{(1*v,1*w),(2*v,2*w),(4*v,4*w)}就可以表示所有的可能性

    再如10 2^0=1,2^1=2,2^2=4。1 2 4 可以组成0~7的所有情况,10-7=3 ,还需要加入一个3 ,只需{(1*v,1*w),(2*v,2*w),(3*v,3*w),(4*v,4*w)}就可以表示所有的可能性

    共有n个物品,背包总重量为m。
    物品i 的价值为v,重量为w,最多个数为s
    struct Good
    {
        int v,w        
    };//存价值和重量
    int main()
    {
        ''''''
        for(int i=0;i<n;i++)
        {
            cin>>v>>w>>s;
            for(int k=1;k<=s;k*=2)
            {
                s-=k;
                goods.push_back({v*k,w*k});
            }    
            if(s>0) goods.push_back(v*s,w*s);
        }
        ''''''''
        同01背包
    }

    七、买股票问题

    买股票问题可以用一个模型来解决:参考文章

    dp[i][k][j]=W表示第i天,剩余可交易次数为k,j=0未持有股票 j=1持有股票

    dp[i][k][0]=max( dp[i-1][k][0] , dp[i-1][k][1]+prise[i] )     当前i天未持有股票   -> 前一天就没有持有 或者 前一天持有今天卖出了

    dp[i][k][1]=max( dp[i-1][k][1] , dp[i-1][k-1][0]-prise[i] )   当前i天持有股票   -> 前一天就持有 或者 前一天未持有今天买入了

    k当只能交易一次,或者可以交易无限次时无效直接去掉。   

    只能交易一次dp[i-1][k-1][0]项无效去掉

    leetcode 121. 买卖股票的最佳时机    交易一次

    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
            if(prices.size()==0)
                return 0;
            vector<vector<int>>dp(prices.size(),vector<int>(2,0));
            dp[0][0]=0;
            dp[0][1]=-1*prices[0];
            for(int i=1;i<prices.size();i++)
            {
                dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);
                dp[i][1]=max(dp[i-1][1],-prices[i]);
            }
            return dp[prices.size()-1][0];
        }
    };
    View Code

    leetcode 122. 买卖股票的最佳时机 II   交易无限次

    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
            if(prices.size()==0)
                return 0;
            vector<vector<int>>dp(prices.size(),vector<int>(2,0));
            dp[0][0]=0;
            dp[0][1]=-prices[0];
            for(int i=1;i<prices.size();i++)
            {
                dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);
                dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]);
            }
            return dp[prices.size()-1][0];
        }
    };
    View Code

    leetcode 123. 买卖股票的最佳时机 III 交易两次

    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
            if(prices.size()==0)
                return 0;
            vector<vector<vector<int> > >dp=(vector<vector<vector<int> > >(prices.size(),vector<vector<int> >(2+1,vector<int>(2,0))));
            dp[0][1][1]=-prices[0];
            dp[0][2][1]=-prices[0];
            for(int i=1;i<prices.size();i++)
            {
                for(int k=2;k>0;k--)
                {
                    dp[i][k][0]=max(dp[i-1][k][0],dp[i-1][k][1]+prices[i]);
                    dp[i][k][1]=max(dp[i-1][k][1],dp[i-1][k-1][0]-prices[i]);
                }
            }
            return max(dp[prices.size()-1][2][0],dp[prices.size()-1][1][0]);
        }
    };
    View Code

    leetcode 188. 买卖股票的最佳时机 IV 最多交易K次

    int minl(int a,int b)
    {
        return (a>b?b:a);
    }
    class Solution {
    public:
        int max_Profit_2(vector<int>& prices) {
            if(prices.size()==0)
                return 0;
            vector<vector<int>>dp(prices.size(),vector<int>(2,0));
            dp[0][0]=0;
            dp[0][1]=-prices[0];
            for(int i=1;i<prices.size();i++)
            {
                dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);
                dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]);
            }
            return dp[prices.size()-1][0];
        }
    
    
        int maxProfit(int k,vector<int>& prices) {
            if(prices.size()==0)
                return 0;
            if(k>prices.size()/2)
                return max_Profit_2(prices);
            vector<vector<vector<int> > >dp=(vector<vector<vector<int> > >(prices.size(),vector<vector<int> >(k+1,vector<int>(2,0))));
            for(int kk=k;kk>0;kk--)    
                dp[0][kk][1]=-prices[0];
            for(int i=1;i<prices.size();i++)
            {
                for(int kk=k;kk>0;kk--)
                {
                    dp[i][kk][0]=max(dp[i-1][kk][0],dp[i-1][kk][1]+prices[i]);
                    dp[i][kk][1]=max(dp[i-1][kk][1],dp[i-1][kk-1][0]-prices[i]);
                }
            }
            int maxl=0;
            for(int kk=k;kk>0;kk--)
                if(dp[prices.size()-1][k][0]>maxl)
                    maxl=dp[prices.size()-1][k][0];
            return maxl;
        }
    };
    View Code

    leetcode 309. 最佳买卖股票时机含冷冻期 冷冻期换成i-2

    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
            if(prices.size()<=1)
                return 0;
            vector<vector<int>>dp(prices.size(),vector<int>(2,0));
            dp[0][1]=-prices[0];
            dp[1][1]=max(dp[0][1],-prices[1]);
            dp[1][0]=max(0,prices[1]-prices[0]);
            for(int i=2;i<prices.size();i++)
            {
                dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);
                dp[i][1]=max(dp[i-1][1],dp[i-2][0]-prices[i]);
            }
            return dp[prices.size()-1][0];
        }
    };
    View Code

    leetcode 714. 买卖股票的最佳时机含手续费 给价格减去交易费

    class Solution {
    public:
        int maxProfit(vector<int>& prices,int fee) {
            if(prices.size()==0)
                return 0;
            vector<vector<int>>dp(prices.size(),vector<int>(2,0));
            dp[0][0]=0;
            dp[0][1]=-prices[0];
            for(int i=1;i<prices.size();i++)
            {
                dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]-fee);
                dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]);
            }
            return dp[prices.size()-1][0];
        }
    };
    View Code

    leetcode 887. 鸡蛋掉落

    常规思路:dp[K][N]表示在存在K个好鸡蛋的情况下要测试N层楼必须的最小尝试次数,

    鸡蛋在dp[K][N]处的下一个状态可能由两个状态组成:max(dp[K][N-i],dp[K-1][i-1]) 在第i层扔过鸡蛋以后没有碎,在第i层扔过鸡蛋以后碎了。i:1->N遍历取最小的一个

    #define inf 999999
    int minl(int a,int b)
    {
        return (a>b?b:a);
    }
    class Solution {
    public:
        
        int dpl(vector<vector<int> >&dp,int K, int N)
        {
            
            int lable=inf;
            if(N==0) return 0;
            if(K==1) return N;
            if(dp[K][N]!=0)
                return dp[K][N];
            for(int i=1;i<=N&&K-1>=0;i++)
            {
                lable=minl(lable,max(dpl(dp,K-1,i-1),dpl(dp,K,N-i))+1);
            }
            dp[K][N]=lable;
            //cout<<K<<"->"<<N<<"->"<<lable<<"  ";
            return lable;
        }
        int superEggDrop(int K, int N) {
            vector<vector<int> >dp(K+1,vector<int>(N+1,0));
            return dpl(dp,K,N);
        }
    };
    超时了

    面试题62. 圆圈中最后剩下的数字

    从最后状态向前推,最后只有一个数字时,也就是0号位置是安全位置,倒着推到最初状态这个0号位置的所在。

    1个人:0

    2个人:(0+m)%2

    3个人:((0+m)%2 +m)%3

    n个人:.......................................%n

    class Solution {
    public:
        int lastRemaining(int n, int m) {
            int out=0;
            for(int i=2;i<=n;i++)
            {
                out=(out+m)%i;
            }
            return out;
        }
    };
    View Code

    leetcode 32. 最长有效括号

    本题需要找好dp的定义。

    dp[i]表示以s[i]为结尾的串有效长度,如图:

    class Solution {
    public:
        int longestValidParentheses(string s) {
            if(s.size()<=1)
                return 0;
            vector<int>dp(s.size(),0);
            int maxl=0;
            if(s[0]=='('&&s[1]==')')
                dp[1]=2;
            for(int i=2;i<s.size();i++)
            {
                if(s[i]=='('){}//A
                else
                {
                    if(s[i-1]=='(')//B
                    {
                        if(i-2<0)//D
                        {
                            dp[i]=2;
                        }
                        else//E
                        {
                            dp[i]=dp[i-2]+2;
                        }
                    }
                    else if(s[i-1]==')')//C
                    {
                        if(i-1-dp[i-1]<0 || s[i-1-dp[i-1]]==')'){}//F
                        else if(s[i-1-dp[i-1]]=='(')//G
                        {
                            if(i-2-dp[i-1]<0)//H
                            {
                                dp[i]=dp[i-1]+2;
                            }
                            else//I
                            {
                                dp[i]=dp[i-1]+2+dp[i-2-dp[i-1]];
                            }
                        }
                    }
                }
            }
            for(int i=0;i<s.size();i++)
                maxl=(dp[i]>maxl?dp[i]:maxl);
            return maxl;
        }
    };
    leetcode32
  • 相关阅读:
    .netcore 通过文件流形式导出Excel,部分列可写,其它列只读实例
    C# NPOI 锁定单元格设置只读
    C# NPOI导出Excel 表格宽度自适应,支持中文
    MySQL 5.7 开启binary log(logbin)及注意事项
    springboot 添加JWT接口认证
    MySql 按姓名 排序
    .netcore3.1 访问静态文件,如图片、Excel等
    Ajax如何设置成同步请求
    项目发布到IIS远程服务器
    在Winform程序中使用Spire.Pdf实现页面添加印章处理(转)
  • 原文地址:https://www.cnblogs.com/dzzy/p/12373960.html
Copyright © 2011-2022 走看看