實現一個Add函數,讓兩個數相加,但是不能使用+、-、*、/等四則運算符。ps:也不能用++、--等等

分析:這又是一道考察發散思維的很有意思的題目。當我們習以爲常的東西被限制使用的時候,如何突破常規去思考,就是解決這個問題的關鍵所在。
看到的這個題目,首先我們可以分析人們是如何做十進制的加法的,比如是如何得出5+17=22這個結果的。
實際上,我們可以分成三步的:
第一步只做各位相加不進位,此時相加的結果是12(個位數5和7相加不要進位是2,十位數0和1相加結果是1);
第二步做進位,5+7中有進位,進位的值是10;第三步把前面兩個結果加起來,12+10的結果是22,剛好5+17=22。
對數字做運算,除了四則運算之外,也就只剩下位運算了。位運算是針對二進制的,我們也就以二進制再來分析一下前面的三步走策略對二進制是不是也管用。
5的二進制是101,17的二進制10001。還是試着把計算分成三步:
第一步各位相加但不計進位,得到的結果是10100(最後一位兩個數都是1,相加的結果是二進制的10。這一步不計進位,因此結果仍然是0);
第二步記下進位。在這個例子中只在最後一位相加時產生一個進位,結果是二進制的10;
第三步把前兩步的結果相加,得到的結果是10110,正好是22。由此可見三步走的策略對二進制也是管用的。
接下來我們試着把二進制上的加法用位運算來替代。

第一步不考慮進位,對每一位相加。0加0與 1加1的結果都0,0加1與1加0的結果都是1。我們可以注意到,這和異或的結果是一樣的。

接着考慮第二步進位,對0加0、0加1、1加0而言,都不會產生進位,只有1加1時,會向前產生一個進位。此時我們可以想象成是兩個數先做位與運算,然後再向左移動一位。只有兩個數都是1的時候,位與得到的結果是1,其餘都是0。

第三步把前兩個步驟的結果相加。如果我們定義一個函數Add(),第三步就相當於輸入前兩步驟的結果來遞歸調用自己。

[cpp] view plain copy
  1. class Solution   
  2. public:  
  3.     int sum = 0;  
  4.     int tmp=0;  
  5.     int Add(int num1, int num2)   
  6.     {  
  7.         if (num2 == 0)  
  8.         {  
  9.             return num1;  
  10.         }  
  11.         else  
  12.         {  
  13.             //第一步,相加不進位    
  14.             sum = num1 ^ num2;  
  15.             //第二步,求得進位的值    
  16.             tmp = (num1 & num2) << 1;  
  17.             //第三步,sum和tmp相加    
  18.             return Add(sum, tmp);  
  19.         }  
  20.     }  
[cpp] view plain copy
  1. //非遞歸版:  
  2.   
  3. /* 
  4. *兩個數異或:相當於每一位相加,而不考慮進位; 
  5. *兩個數相與,並左移一位:相當於求得進位; 
  6. *將兩個新得到的數進行add操作,得到的結果和原本兩個數相加相同, 
  7. *這樣會把num2變得越來越小,知道爲0是,則兩個數的和直接就變成num1. 
  8. */  
  9.   
  10.      int Add(int num1, int num2)  
  11.      {  
  12.         while (num2 != 0)  
  13.         {  
  14.             int temp = num1^num2;  
  15.             num2 = (num1&num2) << 1;  
  16.             num1 = temp;  
  17.         }  
  18.         return num1;  
  19.     }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章