大家好,我是涛哥。
今天,我们来看一道非常有趣的腾讯面试题,小学生就能看懂,但并不容易做对。一起来看看题目,挺有意思的:
有A和B两个杯子和足够的水,杯子容量分别是9升和15升,试判断,能否量出n升的水,如果能,请编程给出步骤。

涛哥手绘
这个题目什么意思呢?我来解释一下:
(1) 先装满A,再装满B,此时A有9升,B有15升。显然,这就量出了24升的水。说白了,就是A + B = 24.
(2) 先装满A,再把A中的水全部倒入B中,此时A为空,B有9升。然后再装满A,继续把A中的水倒入B中,直到B满为止,此时A剩下3升。显然,这就量出了3升的水。说白了,就是2A - B = 2 * 9 - 15 = 3.
一. 逻辑分析
设A = 9,B = 15,我们可以把这两个杯子等价为A = 9,B = 6, 继续等价为A = 3,B = 6,继续等价为A = 3,B = 3,也就是说,最终实际上相当于有一个3升的杯子。所以,能倒出的水必然是3的倍数。
上面这个等价分析过程,其实就是求最大公约数的过程。所以,可以得出规律:A升杯子和B升杯子,可量出的水为 k * gcd(A,B)升。其中K为非负整数,gcd表示最大公约数。所以,原题的判断函数为:
-  
- #include <iostream>
- using namespace std;
-  
- int gcd(int x, int y)
- {  
-   int z = y;
-   while (x % y != 0)
-   {
-     z = x % y;
-     x = y;
-     y = z;  
-   }
-   
-   return z;
- }
-  
- bool can(int A, int B, int n)
- {
-   if (n % gcd(A, B) == 0)
-   {
-     return true;
-   }
-   
-   return false;
- }
-  
- int main()
- {
-    for(int n = 0; n < 20; n++) // test
-    {
-       if (can(9, 15, n) )
-       {
-         cout << n << endl;
-       }
-    }
-  
-    return 0;
- }
结果为:
0
3
6
9
12
15
18
二. 倒水步骤
既然我们已经知道了满足条件的n的值,那么究竟怎样用A和B杯子量出n升的水呢?不妨设A < B,那么当n >= A时,我们总可以从n中不断地减去A,直到减不够为止。这什么意思呢?
其实就是针对任何的n值,我们总可以把它转化为n < A < B这样的问题,比如:A = 9,B = 15,n = 33,我们可以等价为:A = 9,B = 15,n = 33 - 9 - 9 - 9 = 6. 下面,看程序:
-  
- #include<iostream>   
- using namespace std;  
-  
- void pour(int A, int B, int target)
- {
-   //inA, inB分别表示A,B中水的数量
-   int inA = 0;
-   int inB = 0;
-   
-   int flag = 0;
-   while(1)   
-   {   
-     //假设倒水操作可在一定的while循环次数内完成
-     if(flag++ > 999) 
-     {
-       cout << "Fail" << endl;
-       break;
-     }
-  
-     if(0 == inA)   
-     {   
-         cout << "fill A" << endl;
-         inA = A;   
-     }   
-     else  
-     {   
-         cout << "pour A into B" << endl;
-         inB += inA;   
-         
-         if(inB >= B)   
-         {    
-            inA = inB - B;  
-            cout << "empty B" << endl;
-            inB = 0;     
-         }   
-         else  
-         {   
-             inA = 0;   
-         }   
-     }   
-  
-    if(target == inA || target == inB)   
-     {   
-         cout << "Success, OK!" << endl;
-         break;   
-     }   
-   }
- }
-  
- int main()   
- {   
-     int A = 9;
-     int B = 15;
-     int n = 6;
-   
-     //已经证明,任何的A,B,n在该题目中都可以转成如下形式
-     //即:0 <= n < A < B
-     pour(A, B, n);
-  
-   return 0;
- }
结果为:
fill A
pour A into B
fill A
pour A into B
empty B
pour A into B
fill A
pour A into B
fill A
pour A into B
empty B
Success, OK!
这道腾讯面试题并不难,关键还是在于逻辑分析,至于编程实现,那就是顺其自然、水到渠成的事情了。
希望大家举一反三,笔试面试中顺利。又是周五了,是不是感受到了黎明前的黑暗呢?咱们明天周六见。

 
                
![战神引擎传奇手游【黯晶灭世[白猪3.1]】最新整理Win系特色服务端+安卓苹果双端+GM授权后台+详细搭建教程](https://cdn.jxasp.com:9143/image/20251028/0F2E0E55BA6157D5F76B8125D0A511AC.jpg)
















