1. 算法刷题实战:四道经典LeetCode题目精解
今天要和大家分享四道LeetCode经典题目的解题思路和优化技巧。这四道题涵盖了贪心算法、动态规划等核心算法思想,都是面试中的高频考点。我会从问题分析、解法思路到代码实现,一步步拆解每道题目,并分享我在刷题过程中总结的实用技巧。
2. 122. 买卖股票的最佳时机 II
2.1 问题理解与建模
这道题给定一个数组prices,其中prices[i]表示某支股票第i天的价格。我们可以进行多次交易(买入和卖出一支股票算一次交易),但必须在再次购买前出售掉之前的股票。目标是获取最大利润。
例如,对于prices = [7,1,5,3,6,4],最佳策略是在第2天买入(1),第3天卖出(5),利润4;然后在第4天买入(3),第5天卖出(6),利润3。总利润为7。
2.2 贪心算法解法
这道题可以用贪心算法高效解决。核心思想是:只要今天的价格比昨天高,就进行交易(昨天买入今天卖出)。
python复制def maxProfit(prices):
profit = 0
for i in range(1, len(prices)):
if prices[i] > prices[i-1]:
profit += prices[i] - prices[i-1]
return profit
注意:这种解法之所以有效,是因为题目允许在同一天卖出后再买入。实际上相当于可以捕捉到所有的上升段。
2.3 复杂度分析
时间复杂度:O(n),只需要遍历一次数组
空间复杂度:O(1),只使用了常数空间
2.4 常见误区
- 试图寻找全局最低点和最高点:这适用于只能交易一次的情况,但本题允许多次交易
- 过度复杂化:不需要记录每次交易的具体时间点,只需累加所有正收益
3. 55. 跳跃游戏
3.1 问题描述
给定一个非负整数数组nums,你最初位于数组的第一个位置。数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个位置。
例如,nums = [2,3,1,1,4],可以到达最后一个位置(从0跳到1,再从1跳到4)。
3.2 贪心解法
我们可以维护一个变量max_reach,表示当前能到达的最远位置。遍历数组时更新max_reach:
python复制def canJump(nums):
max_reach = 0
for i in range(len(nums)):
if i > max_reach:
return False
max_reach = max(max_reach, i + nums[i])
if max_reach >= len(nums) - 1:
return True
return True
3.3 关键点解析
- 边界条件处理:当i > max_reach时,说明无法到达当前位置
- 提前终止:一旦max_reach >= 最后一个位置,就可以立即返回True
3.4 复杂度分析
时间复杂度:O(n)
空间复杂度:O(1)
4. 45. 跳跃游戏 II
4.1 问题升级
这是跳跃游戏的进阶版,要求找到到达数组末尾的最小跳跃次数。例如,nums = [2,3,1,1,4],最少需要2次跳跃(0→1→4)。
4.2 贪心策略优化
我们需要记录当前跳跃能到达的最远位置(cur_end)和下一步能到达的最远位置(cur_farthest):
python复制def jump(nums):
jumps = 0
cur_end = 0
cur_farthest = 0
for i in range(len(nums)-1):
cur_farthest = max(cur_farthest, i + nums[i])
if i == cur_end:
jumps += 1
cur_end = cur_farthest
return jumps
4.3 算法解释
- 遍历数组时,不断更新下一步能到达的最远位置
- 当到达当前跳跃的边界时,增加跳跃次数并更新边界
- 不需要处理最后一个元素,因为题目保证可以到达终点
4.4 复杂度分析
时间复杂度:O(n)
空间复杂度:O(1)
5. 1005. K次取反后最大化的数组和
5.1 问题理解
给定一个整数数组nums和一个整数k,可以多次选择任意索引i并将nums[i]取反。最多进行k次操作后,返回数组可能的最大和。
例如,nums = [4,2,3], k = 1,最优解是将2取反,得到和为4+(-2)+3=5。
5.2 贪心策略
- 首先将所有负数取反(从小到大)
- 如果还有剩余k,反复取反最小的数(因为对总和影响最小)
python复制def largestSumAfterKNegations(nums, k):
nums.sort()
i = 0
while k > 0 and i < len(nums) and nums[i] < 0:
nums[i] = -nums[i]
k -= 1
i += 1
if k % 2 == 1:
nums.sort()
nums[0] = -nums[0]
return sum(nums)
5.3 关键点
- 优先处理负数,可以最大化总和
- 剩余k为奇数时,只需取反一次最小数(偶数次取反会抵消)
- 需要再次排序找到当前最小数
5.4 复杂度分析
时间复杂度:O(nlogn),主要来自排序
空间复杂度:O(1)或O(n),取决于排序实现
6. 刷题经验分享
在实际刷题过程中,我发现贪心算法类题目有几个共同特点:
- 局部最优解能导致全局最优解
- 通常不需要回溯或考虑所有可能性
- 代码实现往往简洁但思路不易想到
对于这类题目,我的建议是:
- 先尝试几个小例子,观察规律
- 思考如何将问题分解为子问题
- 验证贪心选择的正确性(有时需要数学证明)
在面试中,即使不能立即想到最优解,也可以先提出暴力解法,然后逐步优化。面试官更看重的是你的思考过程,而不仅仅是最终答案。