股票买卖问题

1.买卖股票的最佳时机

使用双指针

i尝试买入,j尝试卖出

遇到涨i不变,j++

遇到跌i变j,j++

package com.dreams.leetcode;

public class Leetcode121 {
    static int maxProfit(int[] prices) {
        int i = 0;
        int j = 1;
        int max = 0;
        while (j < prices.length) {
            if (prices[j] - prices[i] > 0) { // 涨
                max = Math.max(max, prices[j] - prices[i]);
                j++;
            } else { // 跌
                i = j;
                j++;
            }
        }
        return max;
    }

    public static void main(String[] args) {
        System.out.println(maxProfit(new int[]{7, 1, 5, 3, 6, 4})); // 5
        System.out.println(maxProfit(new int[]{9, 3, 12, 1, 2, 3})); // 9
    }
}

 

2.买卖股票的最佳时机 II

贪心思想:

  • 初始化两个指针 i 和 j,分别表示买入点和卖出点,初始时分别指向第一天和第二天的价格。
  • 在一个循环中,不断比较相邻两天的股票价格,并计算利润。
  • 如果当天价格高于前一天,即价格上涨,就计算利润并累加到总利润中。
  • 更新买入点和卖出点,继续向后遍历。
  • 最终返回累计的利润。

代码:

package com.dreams.leetcode;


public class Leetcode122 {

    static int maxProfit(int[] prices) {
        int i = 0;
        int j = 1;
        int sum = 0;
        while (j < prices.length) {
            if (prices[j] - prices[i] > 0) { // 有利润
                sum += prices[j] - prices[i];
            }
            i++;
            j++;
        }
        return sum;
    }

    public static void main(String[] args) {
        System.out.println(maxProfit(new int[]{9, 3, 12, 1, 2, 3})); // 11
        System.out.println(maxProfit(new int[]{7, 1, 5, 3, 6, 4})); // 7
    }
}

 

3.买卖股票的最佳时机含手续费

存在手续费就不能使用贪心算法了

这里使用动态规划

对于买的选择:

  • 延续上次买的利润不变
  • 在上次卖的利润基础上买

对于卖的选择:

  • 延续上次卖的利润不变
  • 在上次买的利润基础上卖

代码:

package com.dreams.leetcode;

public class Leetcode714 {

    static int maxProfit(int[] prices, int fee) {
        int[] buy = new int[prices.length];
        int[] sell = new int[prices.length];
        buy[0] = -prices[0];
        sell[0] = 0;
        for (int i = 1; i < prices.length; i++) {
            buy[i] = Math.max(buy[i - 1], sell[i - 1] - prices[i]);
            sell[i] = Math.max(sell[i - 1], buy[i - 1] + prices[i] - fee);
        }
        return sell[prices.length - 1];
    }

    public static void main(String[] args) {
        // 两次交易的情况
        System.out.println(maxProfit(new int[]{1, 3, 2, 8, 4, 9}, 2)); // 8
        System.out.println(maxProfit(new int[]{1, 3, 7, 2, 18, 3}, 3)); // 16
        System.out.println(maxProfit(new int[]{2, 1, 4, 4, 2, 3, 2, 5, 1, 2}, 1)); // 4
        System.out.println(maxProfit(new int[]{9, 3, 12, 1, 2, 3}, 1)); // 9

        // 一次交易的情况
        System.out.println(maxProfit(new int[]{1, 3, 7, 5, 10, 3}, 3)); // 6
        System.out.println(maxProfit(new int[]{1, 3, 7, 5, 10, 11, 3}, 3)); // 7

    }
}

 

可以看到实际只用到上一个状态,可以优化为一个变量存储

// 根据上次 buy 计算 sell
static int maxProfit1(int[] prices, int fee) {
    int _buy = -prices[0];
    int _sell = 0;
    for (int i = 1; i < prices.length; i++) {
        int buy = Math.max(_buy, _sell - prices[i]);
        int sell = Math.max(_sell, _buy + prices[i] - fee);
        _buy = buy;
        _sell = sell;
    }
    return _sell;
}

 

还有一种优化

// 这种改动虽然业务含义变化了,但对结果不影响, 根据这次 buy 计算 sell
static int maxProfit0(int[] prices, int fee) {
    int buy = -prices[0];
    int sell = 0;
    for (int i = 1; i < prices.length; i++) {
        buy = Math.max(buy, sell - prices[i]);
        sell = Math.max(sell, buy + prices[i] - fee);
    }
    return sell;
}

 

4.买卖股票的最佳时机含冷冻期

代码:

package com.dreams.leetcode;

public class Leetcode309 {
    
    static int maxProfit(int[] prices) {
        if (prices.length == 1) {
            return 0;
        }
        int[] buy = new int[prices.length];
        int[] sell = new int[prices.length];
        buy[0] = -prices[0];
        sell[0] = 0;
        buy[1] = Math.max(-prices[0], -prices[1]);
        sell[1] = Math.max(sell[0], buy[0] + prices[1]);
        for (int i = 2; i < prices.length; i++) {
            buy[i] = Math.max(buy[i - 1], sell[i - 2] - prices[i]);
            sell[i] = Math.max(sell[i - 1], buy[i - 1] + prices[i]);
        }
        return sell[prices.length - 1];
    }

    public static void main(String[] args) {
        System.out.println(maxProfit(new int[]{1, 2, 3, 0, 2})); // 3
    }
}

 

 

5.买卖股票的最佳时机 III

第一次买 不依赖之前状态,以当日价格买入
第一次卖,依赖于昨天第一次买 + 当日价格

第二次买,依赖于昨天第一次卖 – 当日价格
第二次卖,依赖于昨天第二次买 + 当日价格

package com.dreams.leetcode;

public class Leetcode123 {
    static int maxProfit(int[] prices) {
        int buy1 = Integer.MIN_VALUE;
        int sell1 = 0;
        int buy2 = Integer.MIN_VALUE;
        int sell2 = 0;
        for (int price : prices) {
            buy1 = Math.max(buy1, -price);
            sell1 = Math.max(sell1, buy1 + price);

            buy2 = Math.max(buy2, sell1 - price);
            sell2 = Math.max(sell2, buy2 + price);
        }
        return sell2;
    }

    public static void main(String[] args) {
        System.out.println(maxProfit(new int[]{3, 3, 5, 0, 0, 3, 1, 4})); // 6
    }
}

 

6.买卖股票的最佳时机 IV

逻辑:

第一次买 不依赖之前状态,以当日价格买入
第一次卖,依赖于昨天第一次买 + 当日价格

第二次买,依赖于昨天第一次卖 – 当日价格
第二次卖,依赖于昨天第二次买 + 当日价格

第三次买,依赖于昨天第二次卖 – 当日价格
第三次卖,依赖于昨天第三次买 + 当日价格

第 k 次买,依赖于昨天第 k-1 次卖 – 当日价格
第 k 次卖,依赖于昨天第 k 次买 + 当日价格

同时如果k的数目已经大于天数大小的1/2,就使用用于计算不限制交易次数时可以获取的最大利润,其采用了简单的贪心算法,效率会高点。

代码:

package com.dreams.leetcode;

import java.util.Arrays;

public class Leetcode188 {

    static int maxProfit(int[] prices) {
        int i = 0;
        int j = 1;
        int sum = 0;
        while (j < prices.length) {
            if (prices[j] - prices[i] > 0) { // 有利润
                sum += prices[j] - prices[i];
            }
            i++;
            j++;
        }
        return sum;
    }

    static int maxProfit(int k, int[] prices) {
        if (k > prices.length / 2) {
            return maxProfit(prices);
        }
        int[] buy = new int[k];
        int[] sell = new int[k];
        Arrays.fill(buy, Integer.MIN_VALUE);

        for (int price : prices) {
            buy[0] = Math.max(buy[0], -price);
            sell[0] = Math.max(sell[0], buy[0] + price);
            for (int i = 1; i < k; i++) {
                buy[i] = Math.max(buy[i], sell[i - 1] - price);
                sell[i] = Math.max(sell[i], buy[i] + price);
            }
        }
        return sell[k - 1];
    }

    public static void main(String[] args) {
        System.out.println(maxProfit(2, new int[]{3, 2, 6, 5, 0, 3})); // 7
        System.out.println(maxProfit(2, new int[]{3, 3, 5, 0, 0, 3, 1, 4})); // 6
        System.out.println(maxProfit(4, new int[]{1, 2, 0, 1, 0, 3, 1, 4, 5})); // 9
    }
}

 

 

参考

黑马数据结构

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇