当前位置: 首页 > news >正文

Leetcode 20

从现在开始要用c和java都敲一遍了。

1 题目

121. 买卖股票的最佳时机

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

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

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

示例 1:

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

提示:

  • 1 <= prices.length <= 105
  • 0 <= prices[i] <= 104

2 我的想法

最大利润就是a - b的最大差值,并且要求a的索引比b小,如果最大利润a - b 小于0 , 那么就是没有交易完成,也记为0.

写嵌套的for循环?

maxProfit = 0;

for ( int i = 0  ; i ++ ; i <arr.length - 1)

{ for (int  j = 1 ; j ++ ; j < arr.length - 2)

  if (arr [ i ] > arr [ j ])

{

 profit = arr [ i ] - arr [ j ];

if (profit > maxProfit)

{

maxProfit = profit ; }

}

}

return maxProfit;

瞎写,但是我觉得这肯定不是最优的解法,时间复杂度太高了。

这样是可行的吗?一定可以,用hash?还是怎么样?要么是时间换空间,要么是空间换时间。

用c和java实现。

3 实现

你提出的嵌套循环解法虽然可行,但时间复杂度为 O (n²),对于 n=10⁵的情况会超时(超时会怎样?),因此需要更优的解法。

最优解法是使用一次遍历(O (n) 时间复杂度),我们只需要记录当前最低价格和最大利润:

  1. 初始化最低价格为第一个元素,最大利润为 0
  2. 遍历数组,对于每个价格:
    • 如果当前价格低于最低价格,则更新最低价格
    • 否则计算当前价格与最低价格的差值
    • 如果这个差值大于当前最大利润,则更新最大利润

c

#include <stdio.h>
#include <stdlib.h>int maxProfit(int* prices, int pricesSize) {if (pricesSize <= 1) {return 0;}int minPrice = prices[0];  // 记录最低价格int maxProfit = 0;         // 记录最大利润for (int i = 1; i < pricesSize; i++) {// 如果当前价格比最低价格低,更新最低价格if (prices[i] < minPrice) {minPrice = prices[i];} // 否则计算可能的利润else {int profit = prices[i] - minPrice;// 如果当前利润更大,更新最大利润if (profit > maxProfit) {maxProfit = profit;}}}return maxProfit;
}// 测试函数
int main() {int prices1[] = {7,1,5,3,6,4};int size1 = sizeof(prices1) / sizeof(prices1[0]);printf("示例1最大利润: %d\n", maxProfit(prices1, size1));  // 应输出5int prices2[] = {7,6,4,3,1};int size2 = sizeof(prices2) / sizeof(prices2[0]);printf("示例2最大利润: %d\n", maxProfit(prices2, size2));  // 应输出0return 0;
}

java

public class MaxProfit {public int maxProfit(int[] prices) {if (prices == null || prices.length <= 1) {return 0;}int minPrice = prices[0];  // 记录最低价格int maxProfit = 0;         // 记录最大利润for (int i = 1; i < prices.length; i++) {// 如果当前价格比最低价格低,更新最低价格if (prices[i] < minPrice) {minPrice = prices[i];} // 否则计算可能的利润else {int profit = prices[i] - minPrice;// 如果当前利润更大,更新最大利润if (profit > maxProfit) {maxProfit = profit;}}}return maxProfit;}// 测试方法public static void main(String[] args) {MaxProfit solution = new MaxProfit();int[] prices1 = {7,1,5,3,6,4};System.out.println("示例1最大利润: " + solution.maxProfit(prices1));  // 应输出5int[] prices2 = {7,6,4,3,1};System.out.println("示例2最大利润: " + solution.maxProfit(prices2));  // 应输出0}
}

4 关于代码超时

代码超时会直接导致程序无法通过测评,最终判定为 “解答错误” 或 “时间超限”(TLE),哪怕逻辑上能算出正确结果。

简单说,超时就是程序 “跑得太慢了”,超过了测评系统给的时间上限(比如 1 秒),系统会直接终止程序运行,不会等待它算出答案。


⏱️ 为什么你的嵌套循环会超时?

我们用具体数据对比,就能清楚看到差距:

  • 你的嵌套循环(O (n²)):如果数组长度是 10⁵,需要执行 10⁵ × 10⁵ = 10¹⁰ 次操作。
    • 普通计算机每秒大概能处理 10⁸ - 10⁹ 次简单操作,10¹⁰ 次操作需要 10 秒以上,远超时间限制。
  • 最优的一次遍历(O (n)):同样 10⁵长度的数组,只需要执行 10⁵次操作,不到 0.001 秒就能完成,完全符合要求。

这就像你要从 1 楼到 10 楼,嵌套循环是 “走楼梯,每层都往返一次”,而一次遍历是 “坐电梯直达”,效率差距天差地别。


🚫 超时的常见后果

  1. 测评不通过:在 LeetCode、牛客等 OJ(在线判题)平台上,会直接显示 “Time Limit Exceeded (TLE)”,不会给你 “部分得分”。
  2. 实际场景失效:如果这是实际项目中的代码(比如实时处理股票数据),超时会导致程序卡顿、数据堆积,甚至影响整个系统的响应速度。
  3. 暴露算法缺陷:超时本质是算法效率太低,说明你用的解法没有考虑 “数据规模”,这也是面试中面试官会重点关注的点 —— 能算出正确结果只是基础,写出高效代码才是关键。

💡 怎么避免超时?

核心是 “选择更优的算法”,从时间复杂度上降低操作次数:

  • 先分析题目数据规模:比如题目说n ≤ 10⁵,就绝对不能用 O (n²) 的算法,要优先考虑 O (n) 或 O (n log n) 的解法。
  • 减少重复计算:你的嵌套循环里,很多 “价格对比” 是重复的,而一次遍历通过 “记录历史最低价”,直接跳过了这些重复计算。
  • 用空间换时间(必要时):比如有些题目可以用哈希表(HashMap)存已计算的结果,避免重复运算,但本题用常数空间就够了,不需要额外存数据。

常见算法时间复杂度对比表

时间复杂度名称1 秒内可处理的最大数据量典型算法示例适用场景
O(1)常数时间无限制(仅受内存影响)数组访问、哈希表查找简单运算、直接访问数据
O(log n)对数时间10^18 (极大)二分查找、平衡树操作有序数据的快速查找、插入、删除
O(n)线性时间10^8 ~ 10^9线性查找、单链表遍历必须遍历所有元素的场景
O(n log n)线性对数时间10^6 ~ 10^7快速排序、归并排序、堆排序大规模数据的排序操作
O(n²)平方时间10^4 ~ 10^5冒泡排序、插入排序、嵌套循环小规模数据(n≤10⁴)的简单处理
O(n³)立方时间100 ~ 1000矩阵乘法、三重嵌套循环极小规模数据(n≤100)的复杂计算
O(2ⁿ)指数时间20 ~ 30递归解决子集问题、暴力枚举仅适用于 n≤20 的极小问题
O(n!)阶乘时间10 ~ 12全排列生成、旅行商问题暴力解法几乎只用于理论研究,实际中极少使用

关键结论:

  1. 当题目数据规模 n≤10⁴时,O (n²) 算法可能通过;n>10⁴时,必须用 O (n) 或 O (n log n) 算法
  2. 对于股票问题(n≤10⁵),O (n²) 算法会超时,而 O (n) 算法能轻松处理
  3. 指数级和阶乘级复杂度只适用于非常小的输入(n<20)

这个表格可以帮你在做题时快速评估算法可行性,比如看到 n=10⁵,立刻排除 O (n²) 解法,优先考虑线性或线性对数级算法。

5 自己写的错误百出的代码

class Solution {public int maxProfit(int[] prices) {int lowPrice = prices[0];int hopeProfit = 0; if(prices.length <= 1){return 0 ;}else {for (int i = 0 ; i <prices.length - 1 ; i++){int profit = prices[i + 1] - lowPrice;if(prices[i] < lowPrice){lowPrice = prices[i];}hopeProfit = profit;}return hopeProfit;}}
}

详细的错误:

class Solution {public int maxProfit(int[] prices) {// 问题1:未考虑数组为空的情况,直接访问prices[0]会导致空指针异常int lowPrice = prices[0];int hopeProfit = 0; // 问题2:判断条件冗余,数组长度为1时也应该正常处理if(prices.length <= 1){return 0 ;}else {// 问题3:循环范围错误,i只到length-2,最后一个元素prices[length-1]未被处理// 导致无法计算最后一天卖出的利润for (int i = 0 ; i < prices.length - 1 ; i++){// 问题4:计算利润的时机错误// 应该先更新最低价,再计算当前价格的利润// 这里用i+1天的价格减去当前最低价,逻辑混乱int profit = prices[i + 1] - lowPrice;// 问题5:更新最低价的判断条件错误// 用当前i天的价格比较,却没有用i+1天的价格比较// 导致可能错过更低的买入点if(prices[i] < lowPrice){lowPrice = prices[i];}// 问题6:没有保留最大利润,只是简单覆盖// 每次循环都将当前利润直接赋值,会丢失之前的最大利润hopeProfit = profit;}return hopeProfit;}}
}

主要错误总结:

  1. 数组边界问题:当数组为空时,直接访问prices[0]会抛出异常
  2. 循环逻辑错误:循环范围没有包含最后一个元素,导致无法计算最后一天卖出的情况
  3. 利润计算时机错误:先计算利润再更新最低价,导致利润计算基于旧的最低价
  4. 最大利润保存方式错误:没有比较并保留历史最大值,只是简单覆盖
  5. 最低价更新逻辑错误:没有使用当前考察的价格进行比较,可能错过更低的买入点

这些错误共同导致代码无法正确计算出最大利润,比如在价格持续上涨的情况下会得到错误结果,或者在数组为空时直接崩溃。

代码错误点与修复方案对比表

对比维度原错误代码问题修复后代码方案核心原因解析
数组边界处理直接定义 int lowPrice = prices[0],未先判断数组是否为空,若输入空数组会触发 空指针异常先判断 if (prices.length <= 1),满足条件直接返回 0;仅当数组长度≥2 时,再初始化 lowPrice = prices[0]数组操作需先 “防御” 空值 / 短数组场景,避免直接访问索引导致崩溃
循环范围循环条件为 i < prices.length - 1,遍历仅到倒数第二个元素(i 最大为 length-2),最后一个元素未参与计算循环条件改为 i从1开始,i < prices.length,遍历覆盖所有元素(包括最后一个)原逻辑用 prices[i+1] 间接访问后一个元素,但会遗漏最后一个元素的 “卖出” 计算;修复后直接用 prices[i] 处理每个元素,逻辑更直接
最低价更新时机先计算 profit = prices[i+1] - lowPrice,再判断 prices[i] < lowPrice 并更新最低价先判断 prices[i] < lowPrice 并更新最低价,再计算 profit = prices[i] - lowPrice原逻辑 “用旧低价算利润,再更新低价”,会导致利润计算基于过时的低价;正确逻辑应 “先确认当前最低价,再算当前价格的利润”,保证利润计算的时效性
最大利润保存直接赋值 hopeProfit = profit,每次循环覆盖前一次利润,无法保留历史最大利润增加判断 if (profit > maxProfit),仅当当前利润更大时,才更新 maxProfit原逻辑只记录 “最后一次计算的利润”,而非 “所有计算中的最大利润”;修复后通过 “比较 - 保留” 逻辑,确保最终结果是全局最大值
最低价更新对象用 prices[i] 对比更新最低价,但利润却用 prices[i+1] 计算,低价与利润的关联对象错位用 prices[i](当前循环元素)对比更新最低价,同时用 prices[i] 计算利润,两者

6 手敲一遍代码

java

class Solution {public int maxProfit(int[] prices) {if (prices.length <= 1 ){return 0 ;}int maxProfit = 0 ; int lowProfit = prices[0];for (int i = 0 ; i < prices.length -1  ; i ++){if (prices[i] < lowProfit ){lowProfit = prices [i];} int profit = prices[i+1] - lowProfit;if(profit > maxProfit){maxProfit = profit;}} return maxProfit;}
}

c

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

------

一点点小感悟,脱离ide,不要图方便自动补全,练好基本功,这样扎扎实实手敲一遍,不看答案隔天做一遍我感觉自己才掌握了,又进步了!很好!

http://www.dtcms.com/a/391740.html

相关文章:

  • 第五章:离家出走
  • RabbitMQ配置项
  • 用html5写一个时区时间查询器
  • deepseek认为明天CSP-J/S初赛的重点
  • 基于Vue的场景解决
  • 浅谈 Sui 的区块链隐私解决方案
  • ETF期权交易的基础知识是什么?
  • 连接管理模块的实现
  • AI 的耳朵在哪里?—— 语音识别
  • 微博舆情大数据实战项目 Python爬虫+SnowNLP情感+Vue可视化 全栈开发 大数据项目 机器学习✅
  • Dify笔记
  • 高精度维文OCR系统:基于深度学习驱动的实现路径、技术优势与挑战
  • 使用Python+Selenium做自动化测试
  • GESP C++ 三级 2025年6月真题解析
  • Linux系统多线程的互斥问题
  • Python 之监控服务器服务
  • el-select 多选增加全部选项
  • Day24 窗口操作
  • 5. Linux 文件系统基本管理
  • 【MySQL】GROUP BY详解与优化
  • 深度学习:DenseNet 稠密连接​ -- 缓解梯度消失
  • Linux DNS 子域授权实践
  • 团体程序设计天梯赛-练习集 L1-041 寻找250
  • mellanox网卡(ConnectX-7)开启SACK
  • 相机镜头靶面
  • 【语法进阶】gevent的使用与总结
  • Java优选算法——前缀和
  • ARM不同层次开发
  • 【Python】高质量解析 PDF 文件框架和工具
  • RSS-2025 | 无地图具身导航新范式!CREStE:基于互联网规模先验与反事实引导的可扩展无地图导航