牛客_给出股票价格找出买入点和卖出点让利润最大化

博客围绕在整数数组中找最大股票买卖利润展开。先提出问题,给定整数数组代表股票历史价格,要找出买点和卖点使利润最大。接着给出三种思路,分析了不同思路的复杂度,最终得出一种时间复杂度为O(N)、空间复杂度为O(1)的算法。

问题描述:

给你一个整数数组,数组的值代表股票的历史价格。找到买点和卖点,使得利润最大。假设数组为array = {3, 8, 1, 2, 19, 22, 2, 35, 23},那么买点价格是 1, 卖出价格是 35。

思路:

1️⃣、拿到问题的想法就是:我们可以对每个点和其后面的点作比较,找到最大(array[j] - array[i])。因为i 的范围是 0 到 n - 1 (假设数组长度为 n), 而 j 的范围是 i + 1 到 n - 1, 需要对i、j进行两层循环遍历,所以,算法复杂度为 O(N^2)。

2️⃣、因为在第一种想法中始终不确定在访问到底i个位置的时候在此之前的最小买入点是哪一个,那么如果我们有这样一个数组 min[n],里面装的是到 array[i] 值时前面最小的值min[i],比如array = {3, 8, 1, 2, 19, 22, 2, 35, 23},那么 min = {3, 3, 1, 1, 1, 1,1,1, 1}。要得到min数组,只需要遍历一遍array 就可以得到,所以复杂度为 O(N)。 有了min 数组,如果想得到最大的利润,我们只需要再次遍历整数组,让找出最大(array[i] - min[i]) 就可以了。这样做的话,整个算法的时间复杂度还是为 O(N),但是空间复杂度为 O(N)。

3️⃣、在知道了访问到底i个位置的时候在此之前的最小买入点是哪一个的最小值min的时候,我们可以不用去维护这个min数组而是把这个数组改成一个遍历之外的全局变量,即在每次访问的时候都是找到当前的最小买入点min即可。就可以避免方法2️⃣中的空间复杂度O(N)的情况了。

最终:

因为我们要找到 array[j] - array[i] 最大,而且 j > i,我们可以初始化第一个点是买点,第二点是卖点,那么最大利润为 maxProfit = array[1] - array[0]。同时,在向后遍历的时候,我们使用一个临时变量 min 保存比买点更小的值 min,如果 min 后面某一个值,比如 array[k], 减去 min 之后,比目前的利润更大,那么maxProfit就更新为新的最大利润值。

同时用三目运算比较当前的array[i]和min的大小,取其中的最小值作为最新的买入点。那么min就成为了新的买点,array[k]成为了新的卖点。(注意,这个最小值 min 并不一定是最终的买点,因为有可能卖点出现在这个最小值之前。假设数组为array = {3, 81, 1, 2, 19, 22, 2, 35, 23},那么很明显,买点是3,卖点是 81, 而整个数组里,最小值是 1,可是之前的81作为最大卖出点,所带来的收益最大)。有了这两个变量 min 和 maxProfit,我们只需要遍历数组一遍,就可以把整个数组的买点和卖点找出来。

/**
 * @ Author zhangsf
 * @CreateTime 2019/7/13 - 7:47 PM
 */
package com.bjut.qiu;

import java.util.Arrays;

/**
 * 给你一串股票价格,找出买点和卖点,使得利润最大
 * 给你一个整数数组,数组的值代表股票的历史价格。
 * 找到买点和卖点,使得利润最大。
 * 假设数组为array = {3, 8, 1, 2, 19, 22, 2, 35, 23},
 * 那么买点价格是 1, 卖出价格是 35。
 */
public class maxProfit {
    public static void main(String[] args) {
        int array[] ={3, 81, 1, 2, 19, 22, 2, 35, 23};
        System.out.println("测试用例为:        "+ Arrays.toString(array));
        System.out.println("最终的最大利润为:   "+maxProfit(array));
    }
    public static int maxProfit(int[] array) {
        //如果出现边界条件,输入为空,或者数组中个数小于2直接返回0
        if (array == null || array.length < 2)  return 0;
        //我们使用一个临时变量 min 保存比买点更小的值 min,从下标为0的位置开始
        int min = array[0];
        //maxProfit作为最终的利润和,初始化为0
        int maxProfit = 0;
        //开始遍历array数组,从下标1开始,因为已经标记下标0的位置为买点
        for (int i = 1; i < array.length; i++) {
            //如果 min 后面某一个值, 比如 array[i], 减去 min 之后,比目前的利润更大,
            // 那么min就成为了新的买点,array[i]成为了新的卖点
            if ((array[i] - min) > maxProfit) {
                maxProfit = array[i] - min;
            }
            //随着i在不断后移的过程中
            //三目运算,当出现了比买点更小的值的时候就将其值重新赋值给min
            //需要注意的是,min点并不是最终的的买入点,因为可能之后出现了更小的买入点但是前面存在一个卖出点更大的值
            min=array[i] < min?array[i]:min;
        }
        return maxProfit;
    }
}

算法的时间复杂度: O(N)  因为只进行了一次for循环遍历

空间复杂度: O(1) 整个过程中需要的额外空间是两个变量是常数级别的

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangvalue

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值