【算法分析与设计】【第一周】121.&122. Best Time to Buy and Sell Stock I&II

原题来自:121:https://leetcode.com/problems/best-time-to-buy-and-sell-stock/description/

122:https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/description/

第一周,小试牛刀吧。

题目121不复杂,就是英文原题读起来怪怪的。意思是,在保证先买后卖且最多只能买卖一次的情况下,计算最大利润。

思路很简单:逐个求差,差最大且被减数的下标大于减数的下标就可以了。最简单暴力的方法是用两重循环:

int maxProfit(int* prices, int pricesSize) {
    int max = 0;
    for (int i = 0; i < pricesSize; i++) {
        for (int j = i; j < pricesSize; j++) {
            if (prices[j] - prices[i] > max) {
                max = prices[j] - prices[i];
            }
    	}
    }
    return max;
}

显然,此算法的时间复杂度为0(n^2)。根据leetcode给出的分析图,虽然AC,我的方法还有很大的优化空间。

优化的话,思路本质上还是一样的。就是求一个峰值和谷底值之差,且峰值在谷底值后面。主要是能否想到一个巧妙的方法避开双重循环,目前还没想好。

 --------------------------------------------------

做完121,发现还有升级版122。122的意思是,在保证先买后卖且在一个买卖周期内最多只能买卖一次的情况下,计算最大利润。也就是说,卖出之后还可以再进行买入等操作。

这就很有意思了。在没有买卖次数限制的情况下,同样是获得最大利润,情况可以有多种。一开始我是懵的。第一反应是穷举,计算出所有能盈利的情况,再进行比较,得到最大利润。先不说这是个比较浩大的工程量,最重要的是我根本不知道这看似简单的方法从何下手(ˉ▽ˉ;)...。

后来观摩了一下讨论区,发现一位大牛的做法很有意思。大牛的思路很巧妙,就是逐个相减,差大于零就盈利,把盈利的部分加起来;差小于零就进入往后挪,继续相减。哇,简直神奇!把n天切割成n次买卖,每次在第i天买入,第i+1天卖出。只看上升的小段,叠加,忽略下降的小段。

举个简单的例子。对于一种情况{4, 1, 2, 3, 5}来说,最佳盈利策略应当是在1的时候买入,5的时候卖出,盈利为4,一手买卖即可。而按照上面的方法,将这一手买卖分解为1买2卖,2买3卖,3买5卖,共盈利4,三次买卖利润与前面的一手买卖利润一致,但是解释起来更加简便、清晰。

对于另一种情况{4, 1, 3, 2, 5}来说,两个峰,只看上升的小段,看起来就更加清楚了。

这种方法就相当于把长线买卖都简化成了“如果保证盈利,买了马上就卖”的小短线模式的叠加,与周五刚刚学过的“分治”思想还真有异曲同工之妙。

代码实现起来就很简单了:

int maxProfit(int* prices, int pricesSize) {
    int total = 0;
    for (int i=0; i< pricesSize-1; i++) {
        if (prices[i+1] > prices[i]) total += prices[i+1] - prices[i];
    }
    return total;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是本人的一篇OJ实验报告,共涉及五个题目。 一、题目来源:LeetCode 1. Two Sum 问题号:1 题目描述:给定一个整数数组 nums 和一个目标值 target,请在数组中找出和为目标值的两个整数。假设每个输入只对应一种答案,且同样的元素不能被重复利用。 算法思路和分析:使用哈希表(Python中的字典)进行遍历,将数组中的元素作为键,元素下标作为值存入字典中,如果字典中已经存在目标值和当前遍历的元素的差值,则直接返回这两个元素在数组中的下标。 代码: ``` class Solution: def twoSum(self, nums: List[int], target: int) -> List[int]: d = {} for i, num in enumerate(nums): if target - num in d: return [d[target - num], i] d[num] = i return [] ``` 收获心得:通过这个题目,我更加熟悉了Python中的字典以及哈希表的运用,同时也加深了对于遍历的理解。 二、题目来源:LeetCode 15. 3Sum 问题号:15 题目描述:给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。 算法思路和分析:首先将原数组排序,然后使用双指针遍历数组,固定一个数,然后在其后面的数中使用双指针找到另外两个数,使得三数之和为0。为了避免出现重复的三元组,需要在遍历时跳过重复的数。 代码: ``` class Solution: def threeSum(self, nums: List[int]) -> List[List[int]]: nums.sort() res = [] n = len(nums) for i in range(n): if nums[i] > 0: return res if i > 0 and nums[i] == nums[i - 1]: continue l, r = i + 1, n - 1 while l < r: s = nums[i] + nums[l] + nums[r] if s == 0: res.append([nums[i], nums[l], nums[r]]) while l < r and nums[l] == nums[l + 1]: l += 1 while l < r and nums[r] == nums[r - 1]: r -= 1 l += 1 r -= 1 elif s < 0: l += 1 else: r -= 1 return res ``` 收获心得:本题让我更加熟悉了双指针的运用,同时也加强了我对于数组排序和去重的理解。 三、题目来源:LeetCode 70. Climbing Stairs 问题号:70 题目描述:假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 算法思路和分析:爬楼梯问题可以使用动态规划来解决,设f(n)为爬到第n阶的不同方法数,由于每次只能爬1或2个台阶,所以到达第n阶的方法数为到达第n-1阶和到达第n-2阶的方法数之和,即f(n) = f(n-1) + f(n-2)。 代码: ``` class Solution: def climbStairs(self, n: int) -> int: if n == 1: return 1 if n == 2: return 2 dp = [0] * (n + 1) dp[1] = 1 dp[2] = 2 for i in range(3, n + 1): dp[i] = dp[i - 1] + dp[i - 2] return dp[n] ``` 收获心得:通过这个题目,我更加熟悉了动态规划的思想,同时也加强了我对于递推的理解。 四、题目来源:LeetCode 121. Best Time to Buy and Sell Stock 问题号:121 题目描述:给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。你只能选择某一天买入这只股票,并选择在未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。注意:不能在买入股票前卖出股票。 算法思路和分析:使用双指针,一个指向最低价格,一个指向当前价格,遍历整个数组,更新最大利润。 代码: ``` class Solution: def maxProfit(self, prices: List[int]) -> int: if not prices: return 0 min_price = prices[0] max_profit = 0 for price in prices: if price < min_price: min_price = price else: max_profit = max(max_profit, price - min_price) return max_profit ``` 收获心得:本题让我更加熟悉了双指针的运用,同时也加强了我对于数组遍历的理解。 五、题目来源:LeetCode 206. Reverse Linked List 问题号:206 题目描述:反转一个单链表。 算法思路和分析:使用三个指针,分别指向当前节点、前一个节点和后一个节点,遍历整个链表,将每个节点指向前一个节点即可。 代码: ``` class Solution: def reverseList(self, head: ListNode) -> ListNode: if not head or not head.next: return head pre = None cur = head while cur: tmp = cur.next cur.next = pre pre = cur cur = tmp return pre ``` 收获心得:通过这个题目,我更加熟悉了链表的遍历,同时也加强了我对于指针的理解。 以上是我的OJ实验报告,通过这次实验,我学习到了许多算法和数据结构的知识,同时也加强了对于Python语言的熟悉程度,受益匪浅。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值