本文參考自《劍指offer》一書,代碼採用Java語言。html
更多:《劍指Offer》Java實現合集 java
實現函數double Power(double base, int exponent),求base的exponent次方。不得使用庫函數,同時不須要考慮大數問題。面試
這道題很容易實現,但須要注意如下陷阱:1)0的負數次方不存在;2)0的0次方沒有數學意義;3)要考慮exponent爲負數的狀況。因此能夠對exponent進行分類討論,在對base是否爲0進行討論。ide
測試用例函數
指數和底數都分別設置爲正負數和0.post
(含測試代碼)測試
/** * * @Description 面試題16:數值的整數次方 * * @author yongh * @date 2018年9月17日 下午5:17:35 */ // 題目:實現函數double Power(double base, int exponent),求base的exponent // 次方。不得使用庫函數,同時不須要考慮大數問題。 public class Power { boolean IsInvalid = false;//用全局變量標記是否出錯 public double power(double base, int exponent) { IsInvalid = false; double result; // double類型 if (exponent > 0) { result = powerCore(base, exponent); } else if (exponent < 0) { if (base == 0) { IsInvalid = true; //0的負數次方不存在 return 0; } result = 1 / powerCore(base, -exponent); } else { return 1; //這裏0的0次方輸出爲1 } return result; } private double powerCore(double base, int exponent) { if (exponent == 1) return base; if (exponent == 0) return 1; double result = powerCore(base, exponent >> 1); result *= result; if ((exponent & 0x1) == 1) result *= base; return result; } // ========測試代碼======== void test(String testName, double base, int exponent, double expected, boolean expectedFlag) { if (testName != null) System.out.print(testName + ":"); if (power(base, exponent) == expected && IsInvalid == expectedFlag) { System.out.println("passed."); } else { System.out.println("failed."); } } void test1() { test("test1", 0, 6, 0, false); } void test2() { test("test2", 0, -6, 0, true); } void test3() { test("test3", 0, 0, 1, false); } void test4() { test("test4", 2, 6, 64, false); } void test5() { test("test5", 2, -3, 0.125, false); } void test6() { test("test6", 5, 0, 1, false); } void test7() { test("test7", -2, 6, 64, false); } public static void main(String[] args) { Power demo = new Power(); demo.test1(); demo.test2(); demo.test3(); demo.test4(); demo.test5(); demo.test6(); demo.test7(); } }
test1:passed.
test2:passed.
test3:passed.
test4:passed.
test5:passed.
test6:passed.
test7:passed.
非遞歸實現乘方:url
上面的powerCore()方法可改寫以下:spa
/** * 非遞歸實現乘方 */ private double powerCore2(double base, int exponent) { double result=1; while(exponent!=0) { if((exponent&0x1)==1) result*=base; exponent>>=1; base*=base; //指數右移一位,則底數翻倍 //舉例:10^1101 = 10^0001*10^0100*10^1000 //即10^1+10^4+10^8 } return result; }
這道題雖然簡單,但頗有價值,收穫以下:code
1.double類型好像是不能直接用等號判斷,由於存在偏差(這裏暫時用==好像沒問題,不肯定)
2.徹底掌握快速作乘方的訣竅:涉及到求解某數的n次方問題時,能夠採用遞歸來完成,即利用如下公式:
3.使用右移運算符>>代替除以2,有較高的效率:exponent >> 1
4.使用位與運算符代替求餘運算符%判斷奇偶數,有較高的效率:if ((exponent & 0x1) == 1)
(第三第四條之後在除以2時和判斷奇偶時必定要下意識就能想到)
5.不要忽略底數爲0而指數爲負的狀況。
6.非遞歸實現乘方,其本質是根據指數與2的倍數關係來對底數進行操做。
7.if ((exponent & 0x1) == 1) 裏面的小括號必定不能忘記!