LeetCode 121. 买卖股票的最佳时机【简单】

79 阅读2分钟

题干

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

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

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

题解--滑动窗口

本题当然可以使用暴力破解的方法,也就是遍历每一个买点,对于每一个买点,寻找一个卖点,并在遍历的过程用一个变量记录最大的利润,时间复杂度为O(n^2),空间复杂度为O(1)。在这个过程中,有很多次的遍历都是没有必要的。举个例子,prices = [7,1,5,3,6,4],当我们第0天以7块的价格买入后,在寻找卖点时,我们知道第1天的价格为1块,是小于当前买入的价格的,这个时候我们就没必要再往后遍历了,因为我们找到了更低的买点,更低的买点就意味着当前的买点再往后遍历也找不到比这个更低的买点更高的利润了,因此可以将这个更低的点作为新的买点再往后开始遍历。我们可以设置一个滑动窗口,left为滑动窗口的左端点,同时也代表买点,right为滑动窗口的右端点,同时也代表卖点,prices[right] - prices[left]即为当前窗口下的利润,根据上面的思路,我们在发现利润为负的时候,也就是卖点小于买点的时候,可以将滑动窗口向右平移,由此可以写出下面的代码:

func maxProfit(prices []int) int {
	var left int
	var right int = 1
	max := 0
	for right < len(prices) {
		profit := prices[right] - prices[left]
		// 当利润为负时,意味着找到了更低的买点,因此将滑动窗口向右侧平移
		if profit < 0 {
			left = right
			right = left + 1
			continue
		}
		// 当前利润大于最大利润时,记录最大利润
		if profit > max {
			max = profit
		}
		// 滑动窗口右端向右平移,寻找当前买点下的最大利润
		right++
	}
	return max
}

滑动窗口和快慢指针从形式上看很类似,那么他们有什么区别呢?我的理解是这样的,快慢指针的两个指针每次移动时都一格一格动,解的搜索范围在快指针之后;而滑动窗口的两个指针会跳跃着移动,当指针移动时,就意味着窗口的移动,解的搜索范围往往是在窗口的内部的。