牛客网动态规划练习专项版二(C++)

题目1(最长回文子串)

在这里插入图片描述
示例 1
输入:
“ababc”
复制
返回值:
3
复制
说明:
最长的回文子串为"aba"与"bab",长度都为3
示例 2
输入:
“abbba”
复制
返回值:
5
复制
示例 3
输入:
“b”
复制
返回值:
1
复制

收获

1:这道题是自己在尝试那么多的动态回归自己独立写出来的,还是有丢丢成就感滴~

代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param A string字符串
     * @return int整型
     */
    bool isHuiWen(int start,int end,string A){
        int i=start;
        stack<int >st;
        while(i<=end){
            st.push(A[i]);
            i++;
        }
        i=start;
        while(i<=end){
            char temp=st.top();
            st.pop();
            if(A[i]!=temp)
                return false;
            i++;
        }
        return true;
    }
     
    int getLongestPalindrome(string A) {
        // write code here
        vector<int >dp(A.size(),1);
        int maxN=1;
        for(int i=1;i<A.size();i++)
            for(int j=0;j<i;j++){
                if(isHuiWen(j,i,A)&&dp[i]<dp[j]+1){
                    dp[i]=i-j+1;
                    maxN=max(dp[i],maxN);
                }
            }
        return maxN;
    }
};

题目2(打家劫舍一)

在这里插入图片描述

收获

1:这题是可以对每一家进行判断,选择劫舍或不,dp[i]表示至第i家为止能够截取的最大金额

代码

**class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param nums int整型vector
     * @return int整型
     */
    int rob(vector<int>& nums) {
        // write code here
        vector<int>dp(nums.size()+1,0);
        dp[1]=nums[0];
        for(int i=2;i<=nums.size();i++){
            dp[i]=max(dp[i-1],dp[i-2]+nums[i-1]);
        }
        return dp[nums.size()];
    }
};**

题目3(大家劫舍二)

在这里插入图片描述
示例 1
输入:
[1,2,3,4]
复制
返回值:
6
复制
说明:
最优方案是偷第 2 4 个房间
示例 2
输入:
[1,3,6]
复制
返回值:
6
复制
说明:
由于 1 和 3 是相邻的,因此最优方案是偷第 3 个房间

收获

代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param nums int整型vector
     * @return int整型
     */
    int rob(vector<int>& nums) {
        // write code here
        vector<int>dp(nums.size()+1,0);
        //选择偷第一家
        dp[1]=nums[0];
        for(int i=2;i<nums.size();i++){
            //对于每家可以选择偷和不偷
            dp[i]=max(dp[i-1],dp[i-2]+nums[i-1]);
        }
        int res=dp[nums.size()-1];
        dp.clear();
        //选择不偷第一家
        dp[1]=0;
        for(int i=2;i<=nums.size();i++){
            //对于每家可以选择偷和不偷
            dp[i]=max(dp[i-1],dp[i-2]+nums[i-1]);
        }
        return max(res,dp[nums.size()]);
    }
};

题目4(编辑距离一)

在这里插入图片描述
示例 1
输入:
“nowcoder”,“new”
复制
返回值:
6
复制
说明:
“nowcoder”=>“newcoder”(将’o’替换为’e’),修改操作1次
“nowcoder”=>“new”(删除"coder"),删除操作5次
示例 2
输入:
“intention”,“execution”
复制
返回值:
5
复制
说明:
一种方案为:
因为2个长度都是9,后面的4个后缀的长度都为"tion",于是从"inten"到"execu"逐个修改即可
示例 3
输入:
“now”,“nowcoder”
复制
返回值:
5
复制

收获

1:dp[i][j]表示到str1[i],str2[j]为止的子串需要的编辑距离
经典的动态规划解法,记 dp[i][j] 表示将 str10~i 编辑成 str20~j 的代价,如果 str1i=str2j,那么 dp[i][j] 就可以直接从 dp[i-1][j-1] 转移过来,否则就比较插入、删除和替换三种操作哪种的代价小:
如果 str10~i-1 已经编辑成了 str20~j-1,只需要将 str1i 替换为 str2j 可以完成转换,代价为 dp[i-1][j-1]+rc
如果 str10~i-1 已经被编辑为 str20~j,只需要将 str10~i 删除一个 str1i 就可以完成转换,代价为 dp[i-1][j]+dc
如果 str10~i 已经被编辑为 str2 0~j-1,只需要插入一个 str2j 就可以完成转换,代价为 dp[i][j-1]+ic
本题中 3 种编辑代价不做区分,都看做一种操作,因此代价相同。

代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param str1 string字符串
     * @param str2 string字符串
     * @return int整型
     */
    int editDistance(string str1, string str2) {
        // write code here
        int n1=str1.length();
        int n2=str2.length();
        vector<vector<int > >dp(n1+1,vector<int >(n2+1,0));
        for(int i=1;i<=n1;i++)
            dp[i][0]=dp[i-1][0]+1;
        for(int i=1;i<=n2;i++)
            dp[0][i]=dp[0][i-1]+1;
        for(int i=1;i<=n1;i++)
            for(int j=1;j<=n2;j++){
                if(str1[i-1]==str2[j-1])
                    dp[i][j]=dp[i-1][j-1];
                else{
                    dp[i][j]=min(dp[i-1][j-1]+1,min(dp[i-1][j],dp[i][j-1])+1);
                }
            }
        return dp[n1][n2];
    }
};

题目5(买卖股票的最好时机一)

在这里插入图片描述
示例 1
输入:
[8,9,2,5,4,7,1]
复制
返回值:
5
复制
说明:
在第3天(股票价格 = 2)的时候买入,在第6天(股票价格 = 7)的时候卖出,最大利润 = 7-2 = 5 ,不能选择在第2天买入,第3天卖出,这样就亏损7了;同时,你也不能在买入前卖出股票。
示例 2
输入:
[2,4,1]
复制
返回值:
2
复制
示例 3
输入:
[3,2,1]
复制
返回值:
0
复制

收获

1:学会了这种定义大小为2的情况,虽然自己还没有具体的细致理解,但是大概懂了思想

代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param prices int整型vector
     * @return int整型
     */
    int maxProfit(vector<int>& prices) {
        // write code here
        int n=prices.size();
        //dp[i][1]表示某天持股,到该天为止的收益,dp[i][0]表示某天不持股,到该天的最大距离
        vector<vector<int >>dp(n,vector<int >(2,0));
        dp[0][0]=0;
        dp[0][1]=-prices[0];
        for(int i=1;i<n;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[n-1][0];
    }
};

题目6(买卖股票的最好时机二)

在这里插入图片描述
示例 1
输入:
[8,9,2,5,4,7,1]
复制
返回值:
7
复制
说明:
在第1天(股票价格=8)买入,第2天(股票价格=9)卖出,获利9-8=1
在第3天(股票价格=2)买入,第4天(股票价格=5)卖出,获利5-2=3
在第5天(股票价格=4)买入,第6天(股票价格=7)卖出,获利7-4=3
总获利1+3+3=7,返回7
示例 2
输入:
[5,4,3,2,1]
复制
返回值:
0
复制
说明:
由于每天股票都在跌,因此不进行任何交易最优。最大收益为0。
示例 3
输入:
[1,2,3,4,5]
复制
返回值:
4
复制
说明:
第一天买进,最后一天卖出最优。中间的当天买进当天卖出不影响最终结果。最大收益为4。
备注:
总天数不大于200000。保证股票每一天的价格在[1,100]范围内。

收获

代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 计算最大收益
     * @param prices int整型vector 股票每一天的价格
     * @return int整型
     */
    int maxProfit(vector<int>& prices) {
        // write code here
        int n=prices.size();
        //dp[i][1]表示某天持股,到该天为止的收益,dp[i][0]表示某天不持股,到该天的最大距离
        vector<vector<int >>dp(n,vector<int >(2,0));
        dp[0][0]=0;
        dp[0][1]=-prices[0];
        for(int i=1;i<n;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[n-1][0];
    }
};

题目7(买卖股票的最好时机三)

在这里插入图片描述
示例 1
输入:
[8,9,3,5,1,3]
复制
返回值:
4
复制
说明:
第三天(股票价格=3)买进,第四天(股票价格=5)卖出,收益为2
第五天(股票价格=1)买进,第六天(股票价格=3)卖出,收益为2
总收益为4。
示例 2
输入:
[9,8,4,1]
复制
返回值:
0
复制
示例 3
输入:
[1,2,8,3,8]
复制
返回值:
12
复制
说明:
第一笔股票交易在第一天买进,第三天卖出;第二笔股票交易在第四天买进,第五天卖出;总收益为12。
因最多只可以同时持有一只股票,所以不能在第一天进行第一笔股票交易的买进操作,又在第二天进行第二笔股票交易的买进操作(此时第一笔股票交易还没卖出),最后两笔股票交易同时在第三天卖出,也即以上操作不满足题目要求。
备注:
总天数不大于200000。保证股票每一天的价格在[1,100]范围内。

收获

1:定义数组大小为5,并用循环来表示每次处理的值

代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 两次交易所能获得的最大收益
     * @param prices int整型vector 股票每一天的价格
     * @return int整型
     */
    int maxProfit(vector<int>& prices) {
        // write code here
        int n=prices.size();
        vector<vector<int >>dp(n,vector<int >(5,-10000));
        dp[0][0]=0;
        dp[0][1]=-prices[0];
        for(int i=1;i<n;i++){
            dp[i][0]=dp[i-1][0];
            dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]);
            dp[i][2]=max(dp[i-1][2],dp[i-1][1]+prices[i]);
            dp[i][3]=max(dp[i-1][3],dp[i-1][2]-prices[i]);
            dp[i][4]=max(dp[i-1][4],dp[i-1][3]+prices[i]);
        }
        return max(dp[n-1][2],dp[n-1][4]);
    }
};

题目8(最长的括号子串)

在这里插入图片描述
示例 1
输入:
“(()”
复制
返回值:
2
复制
示例 2
输入:
“(())”
复制
返回值:
4
复制

收获

1:采用压栈的方式,左括号入栈,右括号则对当前栈内进行判断,为空怎么样,不为空怎么样,最后使用res进行记录,记得不要忘记设置start为-1即遍历的前一个,同时入栈的是序号而不是左右括号

代码

class Solution {
public:
    /**
     *
     * @param s string字符串
     * @return int整型
     */
    int longestValidParentheses(string s) {
        // write code here
        int start=-1;
        int res=0;
        stack<int >st;
        for(int i=0;i<s.size();i++){
            if(s[i]=='(')
                st.push(i);
            else{
                if(st.empty())
                    start=i;
                else{
                    st.pop();
                if(!st.empty()){
                    res=max(res,i-st.top());
                }else{
                    res=max(res,i-start);
                }
                }
            }
        }
        return res;
    }
};

题目9(正则表达式匹配)

在这里插入图片描述
示例 1
输入:
“aaa”,“aa"
复制
返回值:
true
复制
说明:
中间的
可以出现任意次的a,所以可以出现1次a,能匹配上
示例 2
输入:
“aad”,“cad”
复制
返回值:
true
复制
说明:
因为这里 c 为 0 个,a被重复一次, * 表示零个或多个a。因此可以匹配字符串 “aad”。
示例 3
输入:
“a”,”."
复制
返回值:
true
复制
说明:
".
" 表示可匹配零个或多个('‘)任意字符(’.')
示例 4
输入:
“aaab”,"a
aac"
复制
返回值:
false
复制

收获

1:觉得对正则表达式的理解更多了点,不再像以前那么害怕了

代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param str string字符串
     * @param pattern string字符串
     * @return bool布尔型
     */
    bool match(string str, string pattern) {
        // write code here
        int n1=str.length();
        int n2=pattern.length();
        vector<vector<bool >>dp(n1+1,vector<bool >(n2+1,false));
        dp[0][0]=true;
        //待匹配的字符串为空时的初始化
        for(int i=2;i<=n2;i++){
            if(pattern[i-1]=='*')
                dp[0][i]=dp[0][i-2];
        }
        for(int i=1;i<=n1;i++)
            for(int j=1;j<=n2;j++){
            //当前是.或者相等时
                if(pattern[j-1]!='*'&&(pattern[j-1]=='.'||pattern[j-1]==str[i-1])){
                    dp[i][j]=dp[i-1][j-1];
                }
                //当前是*时
                else if(j>=2&&pattern[j-1]=='*'){
                //如果前一个是.或者前一个和当前的匹配的话,则*起作用,
                //当前的也和当前的匹配,所以dp[i][j]取绝于模板的前2个
                //和字符串的前1个
                    if(pattern[j-2]=='.'||pattern[j-2]==str[i-1])
                        dp[i][j]=dp[i-1][j]||dp[i][j-2];
                    else
                        dp[i][j]=dp[i][j-2];
                }
            }
        return dp[n1][n2];
    }
};

题目10(数字字符转换成ip地址)

在这里插入图片描述
示例 1
输入:
“25525522135”
复制
返回值:
[“255.255.22.135”,“255.255.221.35”]
复制
示例 2
输入:
“1111”
复制
返回值:
[“1.1.1.1”]
复制
示例 3
输入:
“000256”
复制
返回值:
“[]”
复制

收获

1:这道题最开始怎么看也看不懂,看了参考代码不明白,step的意思后来才理解原来是对应的当前处理到第几个数了,因为ip地址最大只能包含4个数字,同时每个字符串内需要处理的最大是3,所以学到了唔~
2:看网上一些说的好像是可以理解为分治的思想,把大问题变成处理这样的小问题,对每一个里面的数字进行判断,再处理一些边界条件,相比较就会容易了一些~

代码

class Solution {
public:
    /**
     * 
     * @param s string字符串 
     * @return string字符串vector
     */
    vector<string >res;
    string nums;
    void dfs(int step,int index,string s){
        string cur="";
        if(step==4){
            if(index!=s.length())
                return;
            res.push_back(nums);
        }else{
            for(int i=index;i<index+3&&i<s.length();i++){
                cur+=s[i];
                int num=stoi(cur);
                string temp=nums;
                if(num<=255&&(cur.length()==1||cur[0]!='0')){
                    if(step-3!=0)
                        nums+=cur+'.';
                    else
                        nums+=cur;
                    dfs(step+1,i+1,s);
                    nums=temp;
                }
            }
        }
    }
    vector<string> restoreIpAddresses(string s) {
        // write code here
        dfs(0,0,s);
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值