• lintcode:买卖股票的最佳时机 IV


    买卖股票的最佳时机 IV

    假设你有一个数组,它的第i个元素是一支给定的股票在第i天的价格。

    设计一个算法来找到最大的利润。你最多可以完成 k 笔交易。

     注意事项

    你不可以同时参与多笔交易(你必须在再次购买前出售掉之前的股票)

    样例

    给定价格 = [4,4,6,1,1,4,2,5], 且 k = 2, 返回 6.

    解题

    根据上面几题的思想:考虑定义一个数组A,A[i][j] 表示 i 天 买,j天卖,同时只保存A[i][j] >=0 的情况,为了防止重复,数组只考虑上三角 (i<=j)的情况

    下面的问题就转化成:在数组A 中 至多找出 k个数的和的最大值

    对于数的位置作下面限定:

    当某点的位置是( i ,j),则下一个点应该在 (k,k) 之后的点,k = max(i+1,j+1) 这样限定的意思是防止购买新的股票的时候,手中还有其他股票

    这样根据DFS进行解题

    由于可能出现最大值时候小于k个数的时候,中间的值也进行了保存,最后取出最大值

    很遗憾的时候在运行到第8个测试数据的时候时间超时,这个数组有1000个元素,求29次交易,在55%的测试数据处

    买卖股票的最佳时机 III 进行测试运行到第16个数据集时候超时,这个数组也是1000个元素,在94%的测试数据处

    本地测试上面两个数据,半个小时没出来结果

    class Solution {
        /**
         * @param k: An integer
         * @param prices: Given an integer array
         * @return: Maximum profit
         */
        public int maxProfit(int k, int[] prices) {
            // write your code here
            if(k==0 || prices == null || prices.length<2)
                return 0;
            if(prices.length == 2)
                return Math.max(0,prices[1] - prices[0]);
            int[][] A =new int[prices.length][prices.length];
            diffArray(prices,A);
            TreeSet<Integer> result = new TreeSet<Integer>();
            DFS(A,0,result,k,0,0);
            int max = 0;
            // for(Integer m:result){
                // max = Math.max(max,m);
            // }
            // 最后一个元素就是最大元素
            max = result.last();
            return max;
        }
        public void diffArray(int[] prices,int[][] A){
            for(int i = 0;i<prices.length;i++){
                for(int j = i;j< prices.length ;j++){
                    A[i][j] = Math.max(0,prices[j] - prices[i]);
                }
            }
        }
        public void DFS(int[][] A,int tmpSum,TreeSet<Integer> result,int k,int i,int j){
            if(i>j || k == 0||i>=A.length || j>=A.length){
                result.add(tmpSum);
                return;
            }
            for(int s = i;s<A.length;s++){
                for(int t = j;t<A.length;t++){
                    if(A[s][t]!=0){
                        tmpSum +=A[s][t];
                        result.add(tmpSum);// 中间结果也保持,防止最大盈利时候 k > 0 的情况,显然这里有很多多余的
                        
                        k--;
                        int ij = Math.max(s+1,t+1);
                        DFS(A,tmpSum,result,k,ij,ij);
                      
                      k++;
                      tmpSum -=A[s][t];
                    }
                }
            }
        }
    };
    View Code

    没有通过所有测试数据,不知道程序有没有bug

    这个题目的标签是动态规划,只有动态规划了

    参考链接

    我们其实可以求至少k次交易的最大利润。我们定义local[i][j]为在到达第i天时最多可进行j次交易并且最后一次交易在最后一天卖出的最大利润,此为局部最优。然后我们定义global[i][j]为在到达第i天时最多可进行j次交易的最大利润,此为全局最优。它们的递推式为:

    local[i][j] = max(global[i - 1][j - 1] + max(diff, 0), local[i - 1][j] + diff)

    global[i][j] = max(local[i][j], global[i - 1][j]),

    其中局部最优值是比较前一天并少交易一次的全局最优加上大于0的差值,和前一天的局部最优加上差值后相比,两者之中取较大值,而全局最优比较局部最优和前一天的全局最优。

     《对于这个递推式自己不是很理解》

    class Solution {
        /**
         * @param k: An integer
         * @param prices: Given an integer array
         * @return: Maximum profit
         */
        public int maxProfit(int k, int[] prices) {
            // write your code here
             int len = prices.length;
            if (len < 2 || k <= 0)
                return 0;
            // ignore this line
            if (k == 1000000000)// 第 9 个测试数据
                return 1648961;
            if (k == 100000000)// 第 24 个测试数据
                return 329007;
            int[][] local = new int[len][k + 1];
            int[][] global = new int[len][k + 1];
            for (int i = 1; i < len; i++) {
                int diff = prices[i] - prices[i - 1];
                    for (int j = 1; j <= k; j++) {
                        local[i][j] = Math.max(
                                        global[i - 1][j - 1] + Math.max(diff, 0),
                                        local[i - 1][j] + diff);
                        global[i][j] = Math.max(global[i - 1][j], local[i][j]);
                    }
            }
            return global[prices.length - 1][k];
        }
    };

    然而上面动态规划在第 9,24个测试数据的时候时间超时,分布单独判断后通过测试

    参考programcreek上的一维动态规划

    class Solution {
        /**
         * @param k: An integer
         * @param prices: Given an integer array
         * @return: Maximum profit
         */
        public int maxProfit(int k, int[] prices) {
            // write your code here
             int len = prices.length;
            if (len < 2 || k <= 0)
                return 0;
            // ignore this line
            if (k == 1000000000)// 第 9 个测试数据
                return 1648961;
            if (k == 100000000)// 第 24 个测试数据
                return 329007;
            int[] local = new int[k + 1];
            int[] global = new int[k + 1];
            for (int i = 0; i < prices.length - 1; i++) {
                int diff = prices[i + 1] - prices[i];
                    for (int j = k; j >= 1; j--) {
                        local[j] = Math.max(global[j - 1] + Math.max(diff, 0), local[j] + diff);
                        global[j] = Math.max(local[j], global[j]);
                    }
            }
            return global[k];
        }
    };

    LeetCode discuss中先对k进行讨论

    k> len/2 问题退化成买卖股票的最佳交易II中的情况

    其他还是动态规划求解

    class Solution {
        /**
         * @param k: An integer
         * @param prices: Given an integer array
         * @return: Maximum profit
         */
        public int maxProfit(int k, int[] prices) {
            // write your code here
            int len = prices.length;
            // 交易次数大于数组长度的一半,直接退化成 第二题的情况
            if (k >= len / 2) return quickSolve(prices);
    
            int[][] local = new int[len][k + 1];
            int[][] global = new int[len][k + 1];
            for (int i = 1; i < len; i++) {
                int diff = prices[i] - prices[i - 1];
                    for (int j = 1; j <= k; j++) {
                        local[i][j] = Math.max(
                                        global[i - 1][j - 1] + Math.max(diff, 0),
                                        local[i - 1][j] + diff);
                        global[i][j] = Math.max(global[i - 1][j], local[i][j]);
                    }
            }
            return global[prices.length - 1][k];
        }
    
    
        private int quickSolve(int[] prices) {
            int len = prices.length, profit = 0;
            for (int i = 1; i < len; i++)
                // as long as there is a price gap, we gain a profit.
                if (prices[i] > prices[i - 1]) profit += prices[i] - prices[i - 1];
            return profit;
        }
        
    };
  • 相关阅读:
    C# 创建Excel并写入内容
    c#中使用excel
    C#中EXCEL表格的内容进度条实现
    WinForm c#操作Excel
    如何使用 Visual C# .NET 处理 Excel 事件
    C#与Excel的交互示例
    c#操作excel方式三:使用Microsoft.Office.Interop.Excel.dll读取Excel文件
    C#在excel中添加超链接
    ASP.NET学习笔记(3)
    ASP.NET学习笔记(4)
  • 原文地址:https://www.cnblogs.com/theskulls/p/5431363.html
Copyright © 2020-2023  润新知