力扣 121.买卖股票的最佳时机的四种解法

115 阅读3分钟

121. 买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

分析:这道题虽然是力扣easy的题,但是有多种解法很适合练手

思路:贪心

贪心1

这种解法类似于53. 最大子数组和 解题思路

首先要明白一个公式: nums[j] - nums[i] = nums[j] - nums[k] + (nums[k] - nums[i]), 即可以把求两点的差值变成求多点差值之和

把两个节点的差值看成一个节点,这样就可以把问题转换成 求数组的连续子序列的和

func maxProfit(prices []int) int {
    max := 0
    num := 0
    for i := 1; i < len(prices); i++ {
       num += prices[i] - prices[i-1]

       if num < 0 {
          num = 0
       } else {
          if num > max {
             max = num
          }
       }

    }
    return max
}

贪心2

第二种解法还是贪心,即找到这个节点左边最小的值并记录下来,直接求两点的差值

不断遍历,如果有更小的值,就直接更新最小值

func maxProfit(prices []int) int {
	if len(prices) == 0 {
		return 0
	}
	min := prices[0]
	max := 0
	for i := 1; i < len(prices); i++ {
		ans := prices[i] - min
		if max < ans {
			max = ans
		}
		if prices[i] < min {
			min = prices[i]
		}
	}
	return max
}

思路2:dp

dp解法1

这个思路其实类似于最大字数和的dp思路,先搞明白这个就可以能明白这个思路

首先还是要明白 nums[j] - nums[i] = (nums[j] - nums[k]) + (nums[k] - nums[i])

dp[i]以i节点卖出的股票最大收益

所以dp[i+1] = dp[i] + prices[i+1] - prices[i]

这是判断如果dp[i+1] < 0,可以舍弃掉这个记录,直接从0开始,dp[i+1] = 0

初始化顺序,dp[0] = 0,第一天没买入,没法卖

举例论证:3,1,2,4

func maxProfit(prices []int) int {
    max := 0
    dp := make([]int, len(prices))
    for i := 1; i < len(prices); i++ {
       dp[i] = dp[i-1] + prices[i] - prices[i-1]
       if dp[i] < 0 {
          dp[i] = 0
       }
       if dp[i] > max {
          max = dp[i]
       }
    }
    //fmt.Println(dp)
    return max
}

dp解法2

这种思想类似穷举

股票分为持有和不持有两种状态

dp[i][0] 持有股票,dp[i][1]在i节点不持有股票

状态转移公式分情况讨论:

dp[i][0]: 如果昨天不持有 dp[i][0] = - p[i]; 如果昨天持有 dp[i][0] = dp[i-1][0]

dp[i][1]: 如果昨天没持有 dp[i][1] = dp[i-1][1]; 如果昨天持有 dp[i][1] = p[i] + dp[i-1][0]

初始化:dp[0][0] = -p[0],dp[0][1] = 0

func maxProfit(prices []int) int {
    dp := make([][2]int, len(prices))
    // 初始化
    dp[0][0] = -prices[0]

    for i := 1; i < len(prices); i++ {
       dp[i][0] = maxInt(dp[i-1][0], -prices[i])
       dp[i][1] = maxInt(prices[i]+dp[i-1][0], dp[i-1][1])
    }
    return dp[len(prices)-1][1]
}

func maxInt(x, y int) int {
    if x > y {
       return x
    }
    return y
}