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循环的解决办法如下:

  

for三层循环 python 3层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;    根据这种思路的代码如下:

     

for三层循环 python 3层for循环优化_时间复杂度_02

 

这次结果是对的,但是循环次数已经降到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

本质上是:人为已经把a、b、c的取值计算方式想好,只是通过计算机落实而已!前面两种方式纯粹是通过计算机的算力暴力求解,后面这种是人为优化解法!

    

for三层循环 python 3层for循环优化_时间复杂度_03

 


    循环次数进一步降到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);
    }


}