腾讯面试:你会倒水吗?

大家好,我是涛哥。

 

今天,我们来看一道非常有趣的腾讯面试题,小学生就能看懂,但并不容易做对。一起来看看题目,挺有意思的:

有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!

这道腾讯面试题并不难,关键还是在于逻辑分析,至于编程实现,那就是顺其自然、水到渠成的事情了。

希望大家举一反三,笔试面试中顺利。又是周五了,是不是感受到了黎明前的黑暗呢?咱们明天周六见。

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值