面试此题时,如果回答递归求解,那就贻笑大方了
int fabonacci(int n) { if(n == 0) return 0; if(n == 1) return 1; return fabonacci(n - 1) + fabonacci(n - 2); }
上述复杂度是指数级的,O(2^n)
如果用表来存储可以降低到O(n)
#include <iostream> using namespace std; #define MAX 20 int fabonacci(int n, int *table) { if(n == 0) return 0; if(n == 1) return 1; if(table[n - 1]) return table[n - 1]; table[n - 1] = fabonacci(n - 1, table) + fabonacci(n - 2, table); return table[n - 1]; } void main() { int *table = new int[MAX]; memset(table, 0, sizeof(int) * MAX); for(int i = 0; i < MAX; i++) { int result = fabonacci(i, table); cout << "result[" << i << "]" << " = " << result << endl; if(i && i % 10 == 0) cout << endl; } delete[] table; }
其实面试官最希望听到的是下面的解法:
/* 利用公式 [f(n), f(n-1)] = [f(n-1), f(n-2)]*A; 矩阵A是x2矩阵 */ /* * Copyright (c) 2011 alexingcool. All Rights Reserved. */ #include <iostream> #include <algorithm> #include <cassert> using namespace std; int array[] = {1, 1, 1, 0}; const int size = sizeof array / sizeof *array; class Matrix { public: Matrix(int (&array)[size]) { for(int i = 0; i < N; i++) for(int j = 0; j < N; j++) data[i][j] = array[i * N + j]; } Matrix() { for(int i = 0; i < N; i++) for(int j = 0; j < N; j++) data[i][j] = 0; } Matrix(const Matrix &rhs) { for(int i = 0; i < N; i++) for(int j = 0; j < N; j++) data[i][j] = rhs.data[i][j]; } int getFabonacci() { return data[0][0] + data[1][0]; } void printMatrix() { for(int i = 0; i < N; i++) { for(int j = 0; j < N; j++) { cout << data[i][j] << " "; } cout << endl; } } void copy(const Matrix &rhs) { for(int i = 0; i < N; i++) { for(int j = 0; j < N; j++) { data[i][j] = rhs.data[i][j]; } } } static int getSize() { return N; } friend const Matrix operator * (const Matrix &lhs, const Matrix &rhs); Matrix& operator *= (const Matrix &rhs); private: static const int N = 2; int data[N][N]; }; const int Matrix::N; Matrix& Matrix::operator *=(const Matrix &rhs) { Matrix result; for(int i = 0; i < N; i++) { for(int j = 0; j < N; j++) { for(int k = 0; k < N; k++) { result.data[i][j] += data[i][k] * rhs.data[k][j]; } } } copy(result); return *this; } const Matrix operator * (const Matrix &lhs, const Matrix &rhs) { Matrix result; int N = Matrix::getSize(); for(int i = 0; i < N; i++) { for(int j = 0; j < N; j++) { for(int k = 0; k < N; k++) { result.data[i][j] += lhs.data[i][k] * rhs.data[k][j]; } } } return result; } const Matrix matrixPow(const Matrix &base, int num) { assert(num >= 0); int mat[size] = {1, 0, 0, 1}; Matrix matrix(mat); Matrix temp = base; if(num < 0) { cerr << "num must be larger than 0" << endl; exit(0); } for(; num; num >>= 1) { if(num & 0x01) matrix *= temp; temp *= temp; } return matrix; } int fabonacci(int n) { if(n <= 0) return 0; if(n == 1) return 1; Matrix matrix(array); matrix = matrixPow(matrix, n - 1); return matrix.getFabonacci(); } void main() { Matrix mat(array); mat = matrixPow(mat, 3); mat.printMatrix(); } 尤其是关于N此方的计算,这个才是关键之所在,下面继续看下一道题,也是我在百度intern二面的题
实现函数double power(double base, int exponent),求base的exponent次方
我当时不假思索的写下下面的code:
double power(double base, int exponent) { double result = 1.0; for(int i = 0; i < exponent; i++) result *= base; return result; }
随后面试官要求我写测试用例:
我按照正数、零、负数、极端写下以下用例
极小值 | 负数 | 零 | 正数 | 极大值 | |
base | -2^30 | -10.0 | 0 | 10.0 | 2^30 |
exponent | none | -10 | 0 | 10 | 2^30 |
所以上述代码得相应更改为:
double power(double base, int exponent) { assert(exponent >= 0); double result = 1.0; if(exponent < 0) { cerr << "exponent must be larger than 0" << endl; return -1; } for(int i = 0; i < exponent; i++) result *= base; return result; }
然后他问我性能上能否优化,我想的方法不怎么好,但实质性还是O(logn)级的复杂度
base^exponent,将exponent除2,如果是偶数,就是base^(exponent >> 1) * base^(exponent >> 1),若是奇数,
则为base^(exponent >> 1) * base(exponent >> 1 + 1),然后一直这样分解。
他说这个方法代码不怎么好写,我觉得还是不难的,下面是我这个方法的代码
(其实,面试官对标准答案有先入为主的意识,对应聘者保持怀疑态度)
/* * Copyright (c) 2011 alexingcool. All Rights Reserved. * 方法绝对原创,此方法转载请注明出处! * spend three hours, please respect my work. 7.13.2011 */ #include <iostream> #include <iterator> #include <algorithm> #include <cassert> using namespace std; #define INF 65535 double _power(double base, int exponent, double *table) { double result = 1.0; if(exponent == 0) return 1.0; if(table[exponent - 1] == 0 || table[exponent - 1] == INF) { if(exponent & 0x01) { if(exponent > 1) { table[(exponent >> 1) - 1] = _power(base, exponent >> 1, table); table[exponent >> 1] = _power(base, (exponent >> 1) + 1, table); return table[exponent >> 1] * table[(exponent >> 1) - 1]; } else { table[0] = base; return table[0]; } } else { table[(exponent >> 1) - 1] = _power(base, exponent >> 1, table); return table[(exponent >> 1) - 1] * table[(exponent >> 1) - 1]; } } return table[exponent - 1]; } double power(double base, int exponent) { assert(exponent >= 0); int tableSize = exponent; double *table = new double[tableSize]; for(int i = 0; i < tableSize; i++) { if(i >= (exponent >> 1) + 1) table[i] = INF; else table[i] = 0; } double result = _power(base, exponent, table); delete[] table; return result; } void main() { double base = 2.0; for(int exp = 0; exp < 32; exp++) { double result = power(base, exp); printf("%f^%d = %f\n", base, exp, result); } }
上述方法的辅助空间其实可以缩小一半,只需要一个flag即可
double _power(double base, int exponent, double *table, bool flag) { double result = 1.0; if(exponent == 0) return 1.0; if(table[exponent - 1] == 0 || flag == false) { flag = true; if(exponent & 0x01) { if(exponent > 1) { table[(exponent >> 1) - 1] = _power(base, exponent >> 1, table, flag); table[exponent >> 1] = _power(base, (exponent >> 1) + 1, table, flag); return table[exponent >> 1] * table[(exponent >> 1) - 1]; } else { table[0] = base; return table[0]; } } else { table[(exponent >> 1) - 1] = _power(base, exponent >> 1, table, flag); return table[(exponent >> 1) - 1] * table[(exponent >> 1) - 1]; } } return table[exponent - 1]; } double power(double base, int exponent) { assert(exponent >= 0); int tableSize = exponent >> 1; bool flag = false; double *table = new double[tableSize + 1]; for(int i = 0; i <= tableSize; i++) { table[i] = 0; } double result = _power(base, exponent, table, flag); delete[] table; return result; }
那么那位面试官想要的答案是啥呢,那就是上面Fibonacci数列关于求幂的方法
/* * Copyright (c) 2011 alexingcool. All Rights Reserved. */ #include <iostream> #include <iterator> #include <algorithm> #include <cassert> using namespace std; #define INF 65535 double power(double base, int exponent) { assert(exponent >= 0); double result = 1.0; for(; exponent; exponent >>= 1) { if(exponent & 0x01) result *= base; base *= base; } return result; } void main() { double base = 2.0; for(int i = 0; i < 32; i++) { double result = power(base, i); printf("%f^%d = %f\n", base, i, result); } }