• 题目1537:买卖股票


    题目描述:
    给定一个大小为n的数组,数组的元素a[i]代表第i天的股票价格。
    设计一个算法,计算在最多允许买卖k次(一买一卖记为一次)的条件下的最大收益。
    需要注意的是,你不能同时拥有两份股票。也就是说在下次买入前,你必须把手头上原有的股票先卖掉。
    输入:
    输入可能包含多个测试案例。
    对于每个测试案例,输入的第一行为两个整数n和k(1<=n,k<=1000)。
    输入的第二行包括n个整数,范围在[0,10000),代表数组中的元素。
    输出:
    对应每个测试案例,输出最大获益。
    样例输入:
    5 1
    3 4 5 1 4
    7 2
    1 2 3 5 6 1 7
    样例输出:
    3
    11
    来源:
    Leetcode 加强版本

    本来这一题完全没有思路的。主要是想到了用dp[i]表示前i天的最大收益。但是不知道怎么处理k次。。还是做题太少。这种有两个条件限制的题明显用dp[i][j]来做。比如0-1背包问题,最原始的想法是考虑到背包体积v和i件物品dp[i][j]表示体积不超过j时,前i个物品能达到的最大价值。LCS问题,考虑到两个字符串dp[i][j]表示S1的前x个字符和S2的前j个字符最长公共子序列。

    所以这题dp[i][j]表示前j天完成i次交易获得的最大收入。

    1) dp[0][j] = 0; dp[i][0] = 0;dp[i][1] = 0;

    2)dp[i][j] = max{dp[i][j-1], max{dp[i - 1][k] + a[j] - a[k]}(1<= k <j)} (1<= i<=交易次数, 2<=j<=n)

    总状态数为O(n * k).状态转移方程可以对每个i,维护一个max = dp[i -1][k] - a[k],这样转移次数为O(1),时间复杂度为O(n * k),否则遍历为O(n),时间复杂度为O(n^2 * k)会超时。

    AC代码:

    #include <stdio.h>
     
    const int MAX = 1001;
     
    int dp[MAX][MAX];
     
    int main()
    {
        int list[1010];
        int n, k;
        while(scanf("%d %d", &n, &k) == 2)
        {
            for(int i = 1; i <= n; i++)
                scanf("%d", &list[i]);
            for(int i = 0; i <= n; i++)
            {
                dp[0][i] = 0;
            }
            for(int i = 0; i <= k ;i ++)
            {
                dp[i][0] = 0;
                dp[i][1] = 0;
            }
            for(int i = 1; i <= k; i++)
            {
                int max = dp[i - 1][1] - list[1];
                for(int j = 2; j <= n; j++)
                {
                    dp[i][j] = dp[i][j - 1] > (max + list[j]) ? dp[i][j - 1] : (max + list[j]);
                    int tmp = dp[i - 1][j] - list[j];
                    max = tmp > max ? tmp : max;
                }
            }
            printf("%d
    ", dp[k][n]);
        }
        return 0;
    }
    /**************************************************************
        Problem: 1537
        User: Qinger
        Language: C++
        Result: Accepted
        Time:40 ms
        Memory:4936 kb
    ****************************************************************/
  • 相关阅读:
    LeetCode#13罗马数字转整数
    LeetCode#7整数反转
    LeetCode#1两数之和
    LeetCode#26删除排序数组中的重复项
    LeecCode#1550存在连续三个奇数的数组
    LeetCode#228汇总区间
    LeetCode#1476子矩形查询
    LeetCode#1535找出数组游戏的赢家
    LeetCode#867转置矩阵
    Vue源码——摸着石头过河
  • 原文地址:https://www.cnblogs.com/xyqhello/p/3591672.html
Copyright © 2020-2023  润新知