面试此题时,如果回答递归求解,那就贻笑大方了
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);
}
}