for循环次数优化
1、今天遇到了一道有意思的数学题:
政府采购一批IT配件,总预算10000元,条件如下:
- 移动硬盘每个500,普通硬盘每个300,U盘3个100;
- 所有配件个数加起来100个,并且钱刚好花完;
问题来了: 移动硬盘、普通硬盘、U盘分别买多少个?
这里原理并不复杂,用a、b、c分别表示3种设备的数量,得到如下等式:
a+b+c=100;
a*500+b*300+c*100/3 = 10000;
2、根据上述的限制条件,普通的开发人员不动脑立刻就能想到for循环的解决办法如下:
这么做的时间复杂度是0(N^3);这里还好每次循环只有100次,所以3次循环一共只有10^6次。如果每次循环1000次了,3层嵌套就是10^9=1亿次了,电脑明显会卡顿。如果这样面试大厂,分分钟被面试官教育人生,offer想都不用想了!
3、第一种优化思路:移动硬盘500元一个,10000元最多买20个;普通硬盘300元一个,10000元最多买33个;U盘100元3个,那么U盘个数肯定是3的倍数,换句话说除以3余数是0,所以新的表达式如下:
a+b+c=100;
a*500+b*300+c*100/3 = 10000;
其中: 0=<a<=20; 0=<b<=33; c%3=0&c>=0; 根据这种思路的代码如下:
这次结果是对的,但是循环次数已经降到660次,时间复杂度是O(n^2),少了一个数量级;这种代码普通电脑计算时已经毫无压力!
4、其实还有优化空间,过程推导如下:
- a+b+c=100; ----- 表达式1
- a*500+b*300+c*100/3 = 10000; ----- 表达式2
- 表达式2两边同时除以100,乘以3得到:15a+9b+c=300; -----表达式3
- 由表达式1得到:c=100-a-b, 带入表达式3替换c,最终得到:7a+4b=100 => b = 25-7*a/4;-----表达式4
- 因为b必须是正整数,所以a必须是4的倍数,并且a<=12, 这里记作a=4*i(0=<i<=3);
- 所以b=25-7*(4*i)/4=25-7*i
- 又所以c=100-a-b=100-4*i-(25-7*i)=75+3*i
所以整个代码优化如下:这里只循环4次就搞定了! 本质上是:人为已经把a、b、c的取值计算方式想好,只是通过计算机落实而已!前面两种方式纯粹是通过计算机的算力暴力求解,后面这种是人为优化解法!
循环次数进一步降到4次,时间复杂度降低到O(n);空间复杂度降低到O(1);
完整代码如下:
#include <iostream> #include <ctime> #include <chrono> using std::chrono::high_resolution_clock; using std::chrono::milliseconds; int main() { high_resolution_clock::time_point beginTime1 = high_resolution_clock::now(); for (int a=0; a<=100;a++) { for (int b=0;b<=100;b++) { for (int c = 0; c <= 100; c++) { if ((a*500+b*300+c*100/3 == 10000)&&(a+b+c==100)) { printf("移动硬盘:%d; 普通硬盘:%d; U盘:%d\n",a,b,c); } } } } high_resolution_clock::time_point endTime1 = high_resolution_clock::now(); milliseconds timeInterval1 = std::chrono::duration_cast<milliseconds>(endTime1 - beginTime1); std::cout << "运行耗时:"<< timeInterval1.count() << "ms\n"; printf("===================================================================>\n"); high_resolution_clock::time_point beginTime2 = high_resolution_clock::now(); for (int a = 0; a <= 10000/500; a++) { for (int b = 0; b <= 10000/300; b++) { int c = 100 - a - b; if (c % 3 != 0) continue; if (a * 500 + b * 300 + c * 100 / 3 == 10000) { printf("移动硬盘:%d; 普通硬盘:%d; U盘:%d\n", a, b, c); } } } high_resolution_clock::time_point endTime2 = high_resolution_clock::now(); milliseconds timeInterval2 = std::chrono::duration_cast<milliseconds>(endTime2 - beginTime2); std::cout << "运行耗时:" << timeInterval2.count() << "ms\n"; printf("===================================================================>\n"); for (int i = 0; i <= 3; i++) { printf("移动硬盘:%d; 普通硬盘:%d; U盘:%d\n", 4*i, 25-7*i, 75+3*i); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人