传统弱校HFUT的蒟蒻,真相只有一个

算法复习:动态规划

一、动归引入

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

 

posted @ 2020-02-27 19:38  未名亚柳  阅读(193)  评论(0编辑  收藏  举报