本文介绍: 注意事项这道题和最多买卖两次是一模一样的思路就是把2换成k了但是还是有几个地方需要注意的注意事项含冷冻期,说明一个事儿:即如果你买了的话,你必须是i-2买的,不能是i-1了!!!注意事项有手续费而已,无非就是卖出的时候减去手续费,简单
188. 买卖股票的最佳时机 IV(最多买卖k次)
int maxProfit(int k, vector<int&gt;&amp; prices) {
        int n = prices.size();
        if(n == 0){
            return 0;
        }
        k = min(k, n/2);
        vector<vector<vector<int&gt;&gt;&gt; dp(n+1,vector<vector<int&gt;&gt;(k+1, vector<int&gt;(2, 0)));
        //dp[1][k][0] = 0 &amp;&amp; dp[1][k][1] = -prices[0]
        for(int i = 0; i < k + 1; i++){
            dp[1][i][0] = 0;
            dp[1][i][1] = -prices[0];
        }
        for(int i = 2; i < n + 1; i++){
            for(int j = 1; j < k + 1; j++){
                dp[i][j][0] = max(dp[i-1][j][0], dp[i-1][j][1] + prices[i-1]);
                dp[i][j][1] = max(dp[i-1][j][1], dp[i-1][j-1][0] - prices[i-1]);
            }
        }
        return dp[n][k][0];
    }
309. 最佳买卖股票时机含冷冻期(买卖多次)
  • 注意事项

    含冷冻期,说明一个事儿:即如果你买了的话,你必须是i-2买的,不能是i-1了!!!

int maxProfit(vector<int&gt;&amp; prices) {
        int n = prices.size();
        if(n == 0){
            return 0;
        }
        //尽可能多的完成交易,也就说不限制次数
        vector<vector<int&gt;&gt; dp(n+1, vector<int>(2, 0));
        dp[1][0] = 0;
        dp[1][1] = -prices[0];
        for(int i = 2; i < n + 1; i++){
            dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i-1]);
            dp[i][1] = max(dp[i-1][1], dp[i-2][0] - prices[i-1]);
        }
        return dp[n][0];
    }
714. 买卖股票的最佳时机含手续费(买卖多次)
  • 注意事项

    有手续费而已,无非就是卖出的时候减去手续费,简单

int maxProfit(vector<int>&amp; prices, int fee) {
        int n = prices.size();
        if(n == 0){
            return 0;
        }
        vector<vector<int>> dp(n + 1, vector<int>(2, 0));
        dp[1][0] = 0;
        dp[1][1] = -prices[0];
        for(int i = 2; i < n + 1; i++){
            dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i-1]- fee);
            dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i-1]);
        }
        return dp[n][0];
    }

序列问题

序列问题是常见的算法问题,而且并不好解决。

首先,子序列问题本身就相对子串、子数组更困难一些,因为前者是不连续的序列,而后两者是连续的,就算穷举你都不一定会,更别说求解相关的算法问题了。

而且,子序列问题很可能涉及到两个字符串,比如前文「最长公共序列」,如果没有一定的处理经验,真的不容易想出来。所以本文就来扒一扒子序列问题的套路,其实就有两种模板,相关问题只要往这两种思路上想,十拿九稳。

一般来说,这类问题都是让你求一个最长子序列,因为最短子序列就是一个字符嘛,没啥可问的。一旦涉及到子序列和最值,那几乎可以肯定,考察的是动态规划技巧时间复杂度一般都是 O(n^2)

原因很简单,你想想一个字符串,它的子序列有多少种可能?起码是指数级的吧,这种情况下,不用动态规划技巧,还想怎么着?

既然要用动态规划,那就要定义 dp 数组,找状态转移关系。我们说的两种思路模板,就是 dp 数组定义思路。不同的问题可能需要不同的 dp 数组定义来解决。

674. 最长连续递增序列
  • 注意事项

    贪心足以,不用动态规划了!

int findLengthOfLCIS(vector<int>&amp; nums) {
        int n = nums.size();
        int max_len = 1;
        int count = 1;
        for(int i = 1; i < n ; i++){
            if(nums[i] > nums[i-1]){
                count++;
                max_len = max(max_len, count);
            }else{
                count = 1;
            }
        }
        return max_len;
    }
718. 最长重复子数组
int findLength(vector<int>&amp; nums1, vector<int>&amp; nums2) {
        int n1 = nums1.size();
        int n2 = nums2.size();
        int max_com = 0;
        vector<vector<int>> dp(n1+1, vector<int>(n2+1, 0));
        for(int i = 1; i < n1 + 1; i++){
            for(int j = 1; j < n2 + 1; j++){
                if(nums1[i-1] == nums2[j-1]){
                    dp[i][j] = dp[i-1][j-1] + 1;
                    max_com = max(max_com, dp[i][j]);
                }
            }   
        }
        return max_com;
    }
int findLength(vector<int>& nums1, vector<int>& nums2) {
    int n1 = nums1.size();
    int n2 = nums2.size();
    return n1 > n2 ? sliding(nums2, nums1) : sliding(nums1, nums2);
}
int sliding(vector<int>& short_vec, vector<int>& long_vec){
    int n1 = short_vec.size();
    int n2 = long_vec.size();
    int max_repeat = 0;

    //短的和长的数组的最右边对齐
    for(int i = 1; i <= n1; i++){
        int tmp = get_repeat(short_vec, 0, long_vec, n2-i,i);
        cout<<"tmp1:"<<tmp<<endl;
        max_repeat = max(tmp, max_repeat);
    }

    //短的和长的数组的最左边对齐
    //以长数组的长度为参考
    for(int i = n2; i - n1>=0; i-- ){
        int tmp = get_repeat(short_vec, 0, long_vec, i-n1, n1);
        cout<<"tmp2:"<<tmp<<endl;
        max_repeat = max(tmp, max_repeat);
    }

    //短数组的右边和长数组的左边对齐
    //以短数组的长度为参考
    for(int i = n1; i >= 1; i--){
        int tmp = get_repeat(short_vec, n1-i, long_vec, 0, i);
        cout<<"tmp3:"<<tmp<<endl;
        max_repeat = max(tmp, max_repeat);
    }
    return max_repeat;
}

int get_repeat(vector<int>& short_vec, int i, vector<int>& long_vec, int j, int common_len){
    int max_repeat = 0;
    int count = 0;    
    for(int index = 0; index < common_len; index++){
        if(short_vec[i+index] == long_vec[j+index]){
            count++;
            max_repeat = max(count, max_repeat);
        }else{
            max_repeat = max(count, max_repeat);
            count = 0;
        }
    }
    return max_repeat;
} 
53. 最大子序和
int maxSubArray(vector<int>& nums) {
        //这道题一眼dp不解释
        int n = nums.size();
        vector<int> dp(n + 1, INT_MIN);
        dp[1] = nums[0];
        for(int i = 2; i < n + 1; i++){
            dp[i] = max(dp[i-1]+nums[i-1], nums[i-1]);
        }
        int max_sum = INT_MIN;
        for(auto n : dp){
            max_sum = max(max_sum, n);
        }
        return max_sum;
    }
⭕️300. 最长递增子序列

这道题第二次做的时候一时间没有想到还。之前我老是想着nums[i-1]与nums[i-2]做匹配,其实是不对的,因为相邻的两个数其实没什么关系,不能这样子比较

int lengthOfLIS(vector<int>& nums) {
    int n = nums.size();
    vector<int> dp(n + 1, 1);
    for(int i = 2; i < n + 1; i++){
        for(int j = 1; j < i; j++){
            if(nums[i - 1] > nums[j - 1]){
                dp[i] = max(dp[i], dp[j] + 1);
            }
        }
    }
    int max_sub = 0;
    for(auto n:dp){
        max_sub = max(max_sub, n);
    }
    return max_sub;
}

int lengthOfLIS(vector<int>& nums) {
    int n = nums.size();
    vector<int> dp(n+1, 1);
    int tmp = nums[0];
    for(int i = 2; i < n + 1; i++){
        int tmp = 1;
        for(int j = 1; j < i; j++){
            if(nums[i-1] > nums[j-1]){
                tmp = max(tmp, dp[j] + 1);
            }
        }
        dp[i] = tmp;
    }
    sort(dp.begin(), dp.end(), std::greater<int>());
    return dp[0];
}

二分

时间复杂度nlogn

维护一个结果数组,如果当前元素比结果数组的值都大的的话,就追加在结果数组后面(相当于递增序列长度加了1);否则的话用当前元素覆盖掉第一个比它大的元素(增长缓慢才可能是最长的)(这样做的话后续递增序列才有可能更长,即使并没有更长,这个覆盖操作也并没有副作用哈,当然这个覆盖操作可能会让最终的结果数组值并不是最终的递增序列值,这无所谓)

操作只有两个:覆盖和追加,只有大于最后一个元素才会追加,其他时候都是覆盖

//比较粗糙的二分,每次循环都求了res数组的大小,效率太低
 int lengthOfLIS(vector<int>& nums) {
     int n = nums.size();
     vector<int> res;
     res.push_back(nums[0]);
     int tmp = nums[0];
     for(int i = 1; i < n; i++){
         if(nums[i] > tmp){
             res.push_back(nums[i]);
             tmp = nums[i];
         }
         else if(tmp == nums[i]){
             continue;
         }
         else{
             int index = lower_bound(res.begin(), res.end(), nums[i]) - res.begin();
             cout<<"nums[i]:"<<nums[i]<<endl;
             cout<<"index:"<<index<<endl;
             res[index] = nums[i];
             int n = res.size();
             tmp = res[n-1];
         }
     }
     return res.size();
 }

//改进的二分
nt lengthOfLIS(vector<int>& nums) {
    int n = nums.size();
    vector<int> res;
    res.push_back(nums[0]);
    int count = 0;
    for(int i = 1; i < n; i++){
        int index = lower_bound(res.begin(), res.end(), nums[i]) - res.begin();
        //之前用的是upper_bound,结果[4,10,4,3,8,9]未通过
        if(index > count){
            res.push_back(nums[i]);
            count++;
        }else{
            res[index] = nums[i];
        }

    }
    return res.size();
}
⭕️1143. 最长公共子序列
  • 最长公共子序列问题是一类问题,包括下面的583和712题,都是一样的

    公共子序列,打表就能做出来了!!典型的打表题

  • 以下是代码部分

    int longestCommonSubsequence(string text1, string text2) {
        int n = text1.size();
        int m = text2.size();
        vector<vector<int>> dp(n+1, vector<int>(m+1, 0));
        for(int i = 1; i < n + 1; i++){
            for(int j = 1; j < m + 1; 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]);
                }
            }
        }
        return dp[n][m];
    }
    

原文地址:https://blog.csdn.net/DeepLearning_/article/details/134604458

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_6049.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注