草庐IT

63.股票的最大利润

木木与呆呆 2023-09-13 原文

链接

https://leetcode-cn.com/problems/gu-piao-de-zui-da-li-run-lcof/
难度: #中等

题目

假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?
示例 1:

输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。

示例 2:

输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

限制:
0 <= 数组长度 <= 10^5
注意:本题与主站 121 题相同:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/

代码框架

class Solution {
    public int maxProfit(int[] prices) {

    }
}

题目解析

解答思路1:
遍历数组,
分别把当前的元素作为买入时机,
把当前元素后面的元素依次作为卖出时机,
从而找到最大利润。

解答思路2:
优化暴利解法,
在寻找第i天后卖出的最佳时机,
存在重复子问题,
优化后避免的重复寻找。

遍历数组,
从第i天开始买入prices[i],
则第i天后面的最大值prices[m]可以卖出,
取profit=Max(profit,prices[m]-prices[i]),
再计算第i+1天的买入prices[i+1],
则第i+1天后面的最大值prices[n]可以卖出,
取profit=Max(profit,prices[n]-prices[j]),
讨论两次最大值prices的下标m和n,
如果m=n,则存在重复子问题,
不需要反复计算下标的最大值,
可以极大的优化暴利解法的性能,
所以需要记录最大值所在的下标m,
可以知道第i到m-1天后面的最大值都是prices[m],

考虑数组[7,1,5,3,6,4]
对应下标[0,1,2,3,4,5]
第0到3次的最大值都是6,下标为4,
第4次由于自己本身是最大值,没有比较的必要了,
后面如果还有其他值,
可以从第m+1个元素开始递归,
重复进行上述操作,
当前最大值前面的值都不需要在考虑了,
因为无论前m-1个元素多小,
后面的最大值已经是第m个元素了,
两者的差值不可能再大了。

解答思路3:
遍历数组一遍,
在遍历第i天的时候,
找出到目前为止当前的最小值,
然后假设自己就是在那一天买的,
不需要确切知道是哪一天买的,
然后在第i天的时候,
计算卖出的利润,
保存利润的最大值,
直到数组遍历完毕,
就能获得最大的利润,
不需要确切知道是哪一天卖的。

解答思路4:
同解答思路3,
但是性能更高,
这里执行用时为0ms,
前面执行用时为1ms。
同时也是一种动态规划的思路。

另外一提,Math.min和max的性能,
高于解答思路3中的比较代码。

解答思路5:
动态规划解法,
使用dp数组记录到第i天时,
买卖股票一次的最大利润,
注意不一定是当天卖出才是最大利润,
即dp[i]最大利润,
要取当前卖出时的利润,
和前一天的最大利润的最大值,
递推公式:
dp[i]=max(dp[i-1],profit);
profit为当天的最大利润,
需要用当天卖出的价格减去前面出现的最小价格,
计算公式为:
profit=prices[i]-min;
min为前i天的最低价格。

测试用例

package edu.yuwen.sowrd.d60.num63.solution;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import edu.yuwen.sowrd.d60.num63.sol5.Solution;

public class SolutionTest {
    /**
     * 示例 1:  
    *   输入: [7,1,5,3,6,4]
    *  输出: 5
    *  解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
    *  注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
     */
    @Test
    public void testCase1() {
        Solution solution = new Solution();

        int[] prices = { 7, 1, 5, 3, 6, 4 };
        int res = solution.maxProfit(prices);
        Assertions.assertEquals(5, res);
    }

    /**
     * 示例 2:
    * 输入: [7,6,4,3,1]
    * 输出: 0
    * 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
     */
    @Test
    public void testCase2() {
        Solution solution = new Solution();

        int[] prices = { 7, 6, 4, 3, 1 };
        int res = solution.maxProfit(prices);
        Assertions.assertEquals(0, res);
    }

    /**
    * 输入: [2,1,4]
    * 输出: 3
    * 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
     */
    @Test
    public void testCase3() {
        Solution solution = new Solution();

        int[] prices = { 2, 1, 4 };
        int res = solution.maxProfit(prices);
        Assertions.assertEquals(3, res);
    }
}

解答1

package edu.yuwen.sowrd.num63.sol1;

public class Solution {
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0) {
            return 0;
        }

        // 初始化最大利润为0
        int max = 0;
        // 买入时机,最后一天无法作为买入时机
        for (int i = 0; i < prices.length - 1; i++) {

            // 卖出时机
            for (int j = i + 1; j < prices.length; j++) {
                // 找出最大利润
                int profit = prices[j] - prices[i];
                max = Math.max(max, profit);
            }
        }

        return max;
    }
}

解答2

package edu.yuwen.sowrd.num63.sol2;

public class Solution {
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0) {
            return 0;
        }

        int profit = 0;
        int maxIndex = -1;
        // 第i天买入时机,最后一天无法买入
        for (int i = 0; i < prices.length - 1; i++) {
            // 最大值的时候,也无法买入
            if (i == maxIndex) {
                continue;
            }
            // i大于最大值的下标,则需要重新查找最大值
            if (i > maxIndex) {
                // 找到i+1到length-1的最大值的下标,左闭右开
                maxIndex = findMax(prices, i + 1);
            }
            profit = Math.max(profit, prices[maxIndex] - prices[i]);
        }

        return profit;
    }

    private int findMax(int[] prices, int i) {
        int max = Integer.MIN_VALUE;
        int maxIndex = -1;
        for (int m = i; m < prices.length; m++) {
            // 找到最大值的下标,且如果有重复的最大值,取索引最大的
            if (max <= prices[m]) {
                max = prices[m];
                maxIndex = m;
            }
        }
        return maxIndex;
    }
}

解答3

package edu.yuwen.sowrd.num63.sol3;

public class Solution {
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0) {
            return 0;
        }

        int profit = 0;
        int min = prices[0];
        for (int i = 1; i < prices.length; i++) {
            // 更新最小值,且买入当天不卖出
            if (min > prices[i]) {
                min = prices[i];
                continue;
            }

            // 更新最大利润
            int newP = prices[i] - min;
            if (profit < newP) {
                profit = newP;
            }
        }
        return profit;
    }
}

解答4 推荐

package edu.yuwen.sowrd.num63.sol4;

public class Solution {
    public int maxProfit(int[] prices) {
        int cost = Integer.MAX_VALUE, profit = 0;
        for (int price : prices) {
            cost = Math.min(cost, price);
            profit = Math.max(profit, price - cost);
        }
        return profit;
    }

}

解答5

package edu.yuwen.sowrd.num63.sol5;

public class Solution {
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0) {
            return 0;
        }

        int[] dp = new int[prices.length];
        // 当天买入卖出利润0
        dp[0] = 0;
        // 前i天的最小值
        int min = prices[0];
        for (int i = 1; i < prices.length; i++) {
            // 更新最小值
            min = Math.min(min, prices[i]);
            // 当天卖出的最大利润
            int profit = prices[i] - min;
            // 前i天买卖一次的最大利润
            dp[i] = Math.max(dp[i - 1], profit);
        }

        return dp[prices.length - 1];
    }
}

有关63.股票的最大利润的更多相关文章

  1. ruby-on-rails - 需要帮助最大化多个相似对象中的 3 个因素并适当排序 - 2

    我需要用任何语言编写一个算法,根据3个因素对数组进行排序。我以度假村为例(如Hipmunk)。假设我想去度假。我想要最便宜的地方、最好的评论和最多的景点。但是,显然我找不到在所有3个中都排名第一的方法。Example(assumingthereare20importantattractions):ResortA:$150/night...98/100infavorablereviews...18of20attractionsResortB:$99/night...85/100infavorablereviews...12of20attractionsResortC:$120/night

  2. ruby - 获取数组中值的最大连续出现次数 - 2

    下面有没有更优雅的方法来实现这个:输入:array=[1,1,1,0,0,1,1,1,1,0]输出:4我的算法:streak=0max_streak=0arr.eachdo|n|ifn==1streak+=1elsemax_streak=streakifstreak>max_streakstreak=0endendputsmax_streak 最佳答案 类似于w0lf'sanswer,但通过从chunk返回nil来跳过元素:array.chunk{|x|x==1||nil}.map{|_,x|x.size}.max

  3. 映宇宙2022年营收63亿元:同比下降三成,毛利率提升4.3个百分点 - 2

    3月26日,映宇宙(HK:03700,即“映客”)发布截至2022年12月31日的2022年度业绩财务报告。财报显示,映宇宙2022年的总营收为63.19亿元,较2021年同期的91.76亿元下降31.1%。2022年,映宇宙的经营亏损为4698.7万元,2021年同期则为净利润4.57亿元;期内亏损(净亏损)为1.68亿元,2021年同期的净利润为4.33亿元;非国际财务报告准则经调整净利润为3.88亿元,2021年同期为4.82亿元,同比下降19.6%。 映宇宙在财报中表示,收入减少主要是由于行业竞争加剧,该集团对旗下产品采取更为谨慎的运营策略以应对市场变化。不过,映宇宙的毛利率则有所提升

  4. ruby-on-rails - 使用 stock_quote gem 中的股票报价作为 acts_as_taggable gem 中的标签? - 2

    所以我正在使用acts_as_taggablegem提供的标签。这些帖子是我正在标记的内容。我怎么能说类似=>的东西(这里是伪代码)ifacollectionofPostshasatagwithacorrespondingStockQuote,displaythestockquote所以现在我有一个acts_as_taggable的Post资源。这是我的帖子索引操作现在的样子:defindex@stock=StockQuote::Stock.quote("symbol")ifparams[:tag]@posts=Post.tagged_with(params[:tag])else@po

  5. ruby - capybara 增加最大允许页面加载时间 - 2

    我有一个页面,有时加载时间超过一分钟。假设这是预期的行为并且不会改变。在这些情况下,我得到Net::ReadTimeout。请注意,这是在通过单击上一页上的按钮导航到页面之后,而不是ajax请求。因此Capybara.using_wait_time没有帮助。我尝试了一些激进的方法(其中一些我知道行不通),例如:设置page.driver.browser.manage.timeouts的implicit_wait、script_timeout和page_load。遍历整个对象空间并设置所有Selenium::WebDriver::Remote::Http::Default的timeout

  6. Ruby - 找到哈希最大值的键 - 2

    我有一个散列,我想返回散列最大值的键(或键/值对)。所以,如果只有一个真正的最大值,它将返回那个键;但是,如果有多个具有相同值的键/值对,它将返回所有这些键。我如何在Ruby中完成此操作?my_hash.max_by{|k,v|v}#onlyreturnsonekey/valuepair 最佳答案 如果你想要所有对,我会做类似的事情max=my_hash.values.maxHash[my_hash.select{|k,v|v==max}] 关于Ruby-找到哈希最大值的键,我们在Sta

  7. Ruby:获取具有最大值的哈希对 - 2

    这是一个哈希值,用于跟踪我拥有的每种水果的数量fruits={"apples"=>10,"pears"=>15,"bananas"=>15,"grapes"=>12}我想知道哪种水果我吃得最多。如果有决胜局,则将它们全部归还。 最佳答案 #easymax_quantity=fruits.values.maxmax_fruits=fruits.select{|k,v|v==max_quantity}.keys#fastmax_quantity=-1.0/0.0max_fruits=[]fruits.eachdo|k,v|ifv>max

  8. ruby-on-rails - 如何在 ruby​​ 中找到跨记录的最大属性? - 2

    我有几个具有多个属性(A、B、C、D)的记录。我希望能够找到哪条记录对于给定属性(例如D)具有更高的值。我该怎么做? 最佳答案 你可能会给出max_by一看。objects=[somearrayofobjects]object_with_highest_value=objects.max_by{|obj|obj.desired_value} 关于ruby-on-rails-如何在ruby​​中找到跨记录的最大属性?,我们在StackOverflow上找到一个类似的问题:

  9. ruby - 如何获取两个数组之间的最大值数组 - 2

    我正在寻找一种优雅的方法来获取包含两个数组之间最大值的数组。意思是如果有两个数组:a=[1,5,9]b=[3,2,11]结果应该是:=>[3,5,11]假设两个数组的大小相同。我使用的代码感觉不像是用Ruby的方式来完成这个任务:c=Array.new(a.size)foriin0...a.sizec[i]=[a[i],b[i]].maxend 最佳答案 这应该有效:[a,b].transpose.map(&:max)#=>[3,5,11]transpose返回[[1,3],[5,2],[9,11]]和map(&:max)找到每个子

  10. ruby - 我天真的最大团发现算法比 Bron-Kerbosch 的运行得更快。怎么了? - 2

    简而言之,我的原始代码(用Ruby编写)如下所示:#$seenisahashtomemoizepreviouslyseensets#$sparseisahashofusernamestoalistofneighboringusernames#$setisthelistofoutputclusters$seen={}defsubgraph(set,adj)hash=(set+adj).sortreturnif$seen[hash]$sets.pushset.sort.join(",")ifadj.empty?andset.size>2adj.each{|node|subgraph(set

随机推荐