問題描述:
- 方法一
採用位運算符實現加法運算。位運算符運算的表格如下:
運算符 |
功能 |
用法 |
說明 |
~ |
位求反 |
~expr |
二進制逐位求反後生成一個新值,0變1,1變0 |
<< |
左移 |
expr1 << expr2 |
在右側插入值爲0的二進制位 |
>> |
右移 |
expr1 >> expr2 |
在左側插入值爲0的二進制位 |
& |
位與 |
expr1 & expr2 |
同爲1取1,否則取0 |
^ |
位異或 |
expr1 ^ expr2 |
相同取0,不同取1 |
| |
位或 |
expr1 | expr2 |
至少有一個爲1,則爲1,否則爲0 |
對於加法運算,先將加數(a)和被加數(b)化成二進制數,然後對 a 和 b 進行位異或(^)運算:異或運算又稱不進位加法、進行位與(&)運算,將這兩個結果相加即可實現加法運算。
例子:
用到的語法:C++中的if....else語法:
if(boolean_expression)
{
//如果不二表達式爲真,將執行此處語句
}
else
{
//如果布爾表達式爲假,將執行此處的語句
}
方法一程序代碼:(遞歸版本)
class Solution {
public:
/**
* @param a: An integer
* @param b: An integer
* @return: The sum of a and b
*/
int aplusb(int a, int b) {
// write your code here
int sum = 0;
int sum1 = a^b; //異或操作,得到二進制原位對應相加之後的和
int sum2 = (a&b)<<1; //與運算和左移運算,得相加之後進位所在位得值
if(sum2 != 0)
{
sum = aplusb(sum1,sum2); //若進位不是0,則a+b的和爲原位和+進位和
}
else
{
sum = sum1; //若進位和爲0,則a+b的和直接等於異或後的結果
}
return sum; //返回加法運算後的結果
}
};
運行時效:
2.方法二(遞歸版本)
使用三目運算符替代if....else語句,提高運行效率。
三目運算符: c ? x : y
若條件c爲true,執行x的值;否則,執行y的值。
方法二的代碼:
class Solution {
public:
/**
* @param a: An integer
* @param b: An integer
* @return: The sum of a and b
*/
int aplusb(int a, int b) {
// write your code here
int sum = 0;
int sum1 = a^b; //異或操作,得到二進制原位對應相加之後的和
int sum2 = (a&b)<<1; //與運算和左移運算,得相加之後進位所在位得值
//使用三目運算符c ? x:y,若條件爲true,則計算x的值,否則,計算y的值
return sum2 == 0 ? sum1 : aplusb(sum1,sum2) ;
}
};
運行時效:
3.方法三:(迭代版本)
class Solution {
public:
/**
* @param a: An integer
* @param b: An integer
* @return: The sum of a and b
*/
//加法運算迭代版
int aplusb(int a, int b) {
// write your code here
int sum =a^b;
int sum1 = (a&b)<<1;
while(sum1 != 0) //不斷迭代,直到爲0跳出循環
{
int a = sum;
int b = sum1;
sum = a^b;
sum1 =(a&b)<<1;
}
return sum;
}
};
運行時效:
迭代和遞歸的區別:
從“編程之美”的角度看,可以借用一句非常經典的話:“迭代是人,遞歸是神!”來從宏觀上對二者進行把握。
- 遞歸:重複調用函數自身實現循環稱爲遞歸;
遞歸實際上不斷地深層調用函數,直到函數有返回纔會逐層的返回,遞歸是用棧機制實現的,每深入一層,都要佔去一塊棧數據區域,因此,遞歸涉及到運行時的堆棧開銷(參數必須壓入堆棧保存,直到該層函數調用返回爲止),所以有可能導致堆棧溢出的錯誤;但是遞歸編程所體現的思想正是人們追求簡潔、將問題交給計算機,以及將大問題分解爲相同小問題從而解決大問題的動機。
例如:if else 調用自己,並在合適時機退出
- 迭代:利用變量的原值推出新值稱爲迭代,或着說迭代是函數內某段代碼實現循環;
迭代大部分時候需要人爲的對問題進行剖析,分析問題的規律所在,將問題轉變爲一次次的迭代來逼近答案。迭代不像遞歸那樣對堆棧有一定的要求,另外一旦問題剖析完畢,就可以很容易的通過循環加以實現。迭代的效率高,但卻不太容易理解,當遇到數據結構的設計時,比如圖表、二叉樹、網格等問題時,使用就比較困難,而是用遞歸就能省掉人工思考解法的過程,只需要不斷的將問題分解直到返回就可以了。
例如:for,while循環
- 兩者關係:所有的迭代可以轉換爲遞歸,但遞歸不一定可以轉換成迭代。
總結如下:
定義 | 優點 | 缺點 | |
遞歸 | 重複調用函數自身實現循環 |
a.用有限的循環語句實現無限集合; b.代碼易讀; c.大問題轉化成小問題,減少了代碼量。 |
a.遞歸不斷調用函數,浪費空間 b.容易造成堆棧溢出 |
迭代 |
利用變量的原值推出新值; 函數內某段代碼實現循環。 |
a.效率高,運行時間只隨循環的增加而增加; b.無額外開銷。 |
a.代碼難理解; b.代碼不如遞歸代碼簡潔; c.編寫複雜問題時,代碼邏輯不易想出 |
兩者關係 |
a.遞歸中一定有迭代,但是迭代中不一定有遞歸;大部分可以相互轉換。 b.相對來說,能用迭代不用遞歸(因爲遞歸不斷調用函數,浪費空間,容易造成堆棧溢出) |