剑指offer-75、买卖股票的最好时机

题⽬描述

假设你有⼀个数组 prices ,⻓度为 n ,其中 pricesi 是股票在第 i 天的价格,请根据这个价格数组,返回买卖股票能获得的最⼤收益

  1. 你可以买⼊⼀次股票和卖出⼀次股票,并⾮每天都可以买⼊或卖出⼀次,总共只能买⼊和卖出⼀次,且买⼊必须在卖出的前⾯的某⼀天
  2. 如果不能获取到任何利润,请返回 0
  3. 假设买⼊卖出均⽆⼿续费

示例1: 输⼊:8,9,2,5,4,7,1 返回值: 5 说明: 在第3天(股票价格 = 2)的时候买⼊,在第6天(股票价格 = 7)的时候卖出,最⼤利润 = 7-2 = 5,不能选择在第2天买⼊,第3天卖出,这样就亏损7了;同时,你也不能在买⼊前卖出股票。

示例2: 输⼊:2,4,1 返回值: 2

思路及解答

暴⼒穷举

这⾥涉及的节点⽆⾮是买⼊,卖出,那么我们遍历所有的数据,作为买⼊⽇期,同时将该⽇期后⾯每⼀个都作为卖出⽇期来计算,只要维护最⼤的利润即可。

java 复制代码
public class Solution {
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length < 2) {
            return 0;
        }
        
        int maxProfit = 0;
        int n = prices.length;
        
        // 外层循环:遍历所有可能的买入点
        for (int i = 0; i < n - 1; i++) {
            // 内层循环:遍历所有可能的卖出点(必须在买入点之后)
            for (int j = i + 1; j < n; j++) {
                int profit = prices[j] - prices[i];
                if (profit > maxProfit) {
                    maxProfit = profit;
                }
            }
        }
        
        return maxProfit;
    }
}
  • 时间复杂度: O(n2)
  • 空间复杂度:O(1)

贪⼼法(最优解)

我们要想得到⼀个最⼤的利润,其实就是要两者差值最⼤。如果让差值最⼤,假设在当天卖出,那么什么时候买⼊最好呢?

当然是在前⾯找到最⼩的买⼊点,⽐如:

⽽前⾯的最⼩值,其实我们在遍历的时候是可以不断维护的,所以我们只要遍历⼀次数组即可。

关键思想:

  • 最大利润 = 某日价格 - 该日之前的最低价格
  • 只需维护两个变量:
    • minPrice:遍历过程中遇到的最低价格
    • maxProfit:当前能获得的最大利润
java 复制代码
public class Solution63 {
    public int maxProfit(int[] prices) {
        int min = Integer.MAX_VALUE;
        int result = 0;
        for (int value: prices) {
            // 维护最⼩值
            min = Math.min(min, value);
            // 当前值减去前⾯最⼩值,与利润最⼤值对⽐,维护好利润最⼤值
            result = Math.max(result, value - min);
        }
        return result;
    }
}
  • 时间复杂度:O(n),只需遍历一次数组
  • 空间复杂度:O(1),只使用常数空间

执行过程示例(prices = 8,9,2,5,4,7,1

text 复制代码
i=0: price=8, minPrice=8, maxProfit=0
i=1: price=9, minPrice=8, maxProfit=1
i=2: price=2, minPrice=2, maxProfit=1
i=3: price=5, minPrice=2, maxProfit=3
i=4: price=4, minPrice=2, maxProfit=3
i=5: price=7, minPrice=2, maxProfit=5
i=6: price=1, minPrice=1, maxProfit=5
结果:5

动态规划

dpi表示前i天的最大利润,状态转移基于前i-1天的结果

状态定义:

  • minPrice[i]:前i天的最低价格
  • maxProfit[i]:前i天能获得的最大利润
java 复制代码
public class Solution {
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length < 2) {
            return 0;
        }
        
        int minPrice = prices[0];
        int maxProfit = 0;
        
        for (int i = 1; i < prices.length; i++) {
            // 状态转移方程:
            // 前i天的最大利润 = max(前i-1天的最大利润, 第i天价格-前i-1天的最低价格)
            maxProfit = Math.max(maxProfit, prices[i] - minPrice);
            minPrice = Math.min(minPrice, prices[i]);
        }
        
        return maxProfit;
    }
}
  • 时间复杂度:O(n),单次遍历
  • 空间复杂度:O(1),优化后只需两个变量
相关推荐
方也_arkling8 小时前
【Java-Day08】static / final / 枚举
java·开发语言
橙淮8 小时前
Spring Bean作用域与生命周期全解析
java·spring
Chengbei118 小时前
一站式源码安全检测工具、云安全 / APP / 小程序源码敏感信息递归多层目录扫描AK、JWT、手机号、身份证等敏感信息
java·开发语言·安全·web安全·网络安全·系统安全·安全架构
llz_1128 小时前
web-第一次课后作业
java·开发语言·idea
秋99 小时前
Java项目运行5天左右自动宕机:系统性定位与解决方案
java·开发语言·python
小江的记录本9 小时前
【JVM虚拟机】垃圾回收GC:垃圾收集器:CMS:核心原理、回收流程、优缺点、废弃原因(附《思维导图》+《面试高频考点清单》)
java·jvm·后端·python·spring·面试·maven
DIY源码阁9 小时前
JavaSwing学生成绩管理系统 - MySQL版
java·数据库·mysql·eclipse
basketball61610 小时前
C++ NULL 和 nullptr 区别 以及 nullptr 的核心实现
java·开发语言·c++
JAVA面经实录91711 小时前
MyBatis面试题库
java·mybatis
小江的记录本11 小时前
【JVM虚拟机】垃圾回收GC:垃圾回收算法:标记-清除、标记-复制、标记-整理、分代收集(附《思维导图》+《面试高频考点清单》)
java·jvm·后端·python·算法·安全·面试