从一到面试题谈起

一道面试题

最近看CSDN,又谈到一道面试题,大致是“不使用比较运算符和库函数比较两个整数的大小”。这种题看似简单,实则深藏玄机,考得不只是技巧还有很多基础知识。

第一种解法

第一种解法是楼主给出的,很简单:

(int)(((long)a – (long)b)>>>63)

代码是Java的,解题的思路也很简单,原理是a-b>=0等同于a>=b而和0的比较可以取符号位进行判断,如果差值为非负数则前者大于或等于后者。因为考虑到溢出,所以使用更长的类型以控制溢出。

当然,对于此题这种解法是正确的,但如果止于此也就没有了这篇文章。

也玩一玩测试

做编码的能够做好测试的人不多,其实编码人员偶尔的接触一些测试的东西也是有好处的。有个接触单元测试很少的同事,在推广单元测试的时候,总怀疑单元测试的用处,简单使用后虽然别的好处没有说,但说了一点确实能够提高质量发现很多开始没有想到的问题。

话题扯远了,既然要解决问题,总得有个测试来验证验证。

函数原型比较简单:bool intLECheck(int int1, int int2),只需把结果和int1>=int2进行比较即可。测试数据也比较简单:第一步考虑覆盖,整数有>0=0<0三种,两个整数也有三种关系><=;第二步考虑边界,整数有最大正整数和最小正整数,在加上0,再加上正好溢出或者正好不溢出的情况,差不多已经覆盖全部边界了;第三步增加测试数据数量,产生一批随机数进行测试。

测试的问题搞定,再回到编码上来。

对第一种解法的思考

第一种解法用到了更长的类型以防止溢出,但是如果没有更长的类型怎么办?有没有其他别的办法进行比较?如果换作无符号整数该怎么做?如果是浮点数又该怎么做?

首先,想一想我们常用的比较大小的方法,可以利用的方法很多:

比如,可以按照一定的顺序在整数中查找两数,先找到的数大,或者小;再比如,用解法一中两数差进行比较;再比如还可以使用两数商进行比较;再比如可以按位比较等等。这里提到的方法都是能够做出来的,顺序查询太费时间空间,按位比较实现比较麻烦。按商比较得考虑除数不为0,还得考虑正数和负数的不同。综合来看,还是用差最为方便和快捷。那可否不使用更长的类型来防止差值的溢出呢?答案是肯定的,先看看整数的编码以及溢出发生的情况。

整数的编码和溢出

整数一般为32位,最高位为符号位1为负数,0为非负数,其他位为数据。整数差值溢出发生在两数之差大于最大整数值或者小于最小整数值。进一步可以发现,当两整数符号位相同时,差值不会溢出。

第二种解决方案

解决溢出问题的另一方法就是拆分。就像一个水杯的水要溢出了,可以考虑换用更大的水杯防止溢出,但没有更大的杯子的时候也可以考虑把水分一些分到其他杯子里,同样也可以防止溢出。

整数的拆分有多种,比如分为两个16位的整数。假设两个整数拆分后分别为int11int12int21int22,显然有:

Int11>int21 => int1>int2

Int11<int21 => int1<int2

Int11==int21 && int12>=int22 => int1>=int2

Int11==int21 && int12<int22=>int1<int2

第三种解决方案

除了前两种方案外,还可以先通过比较符号位来有效规避差值溢出。

解题的乐趣

像很多题目一样,这道题没有太多的现实意义。但题目的意义很多不再于现实,而在于其中含有的知识和思考问题解决问题的方法。过于关注答案,意义不大;一味沉浸其中,则容易陷入其中而少了乐趣。

源代码

附上几种解决方法的代码(C语言版):

测试结果如下:

 

测试结果

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值