第7题:斐波那契数列
题目
大家都知道斐波那契数列,现在要求输入一个整数
n
,请你输出斐波那契数列的第n
项。n<=39
。
解析
斐波那契数列的定义:
- ;
可以从 开始;,不断向前计算,最后得到 ; 也可以采用递归
class Solution {
public:
int Fibonacci(int n) {
if (n == 0)
return 0;
if (n == 1)
return 1;
int f1 = 0, f2 = 1, ret;
// 1)前向计算
for (int i = 2; i <= n; i++)
ret = f1 + f2, f1 = f2, f2 = ret;
// 2) 递归方法
/*
ret = Fibonacci(n-1) + Fibonacci(n-2);
*/
return ret;
}
};
第8题:跳台阶
题目:
一只青蛙一次可以跳上
1
级台阶,也可以跳上2
级。求该青蛙跳上一个n
级的台阶总共有多少种跳法。
解析
最简单的
动态规划
,考虑最后跳上第n阶台阶,有两种方式往上跳:
- 从第n - 1阶往上跳一级到第n阶;
- 从第n - 2阶往上跳二级到第n阶。
那么 表示该青蛙跳上一个i
级的台阶总共跳法 这就是变形版的斐波拉契数列
,直接求解。
class Solution {
public:
int jumpFloor(int n) {
if (n == 1)
return 1;
int f1 = 1, f2 = 1, ret;
for (int i = 2; i <= n; i++)
ret = f1 + f2, f1 = f2, f2 = ret;
return ret;
}
};
第9题: 变态跳台阶
题目:
一只青蛙一次可以跳上
1
级台阶,也可以跳上2
级……它也可以跳上n
级。求该青蛙跳上一个n
级的台阶总共有多少种跳法。
解析
根据上题可以写出下面的公式:
注意到: ,
那么: )
这是一个首项为1,公比为2的等比数列
,直接可以得到最终表达式
class Solution {
public:
int jumpFloorII(int number) {
// 将1左移number-1位
return 1 << (number - 1);
}
};
备注
C++中, i<<num为将i的二进制左移num位,对应十进制放大 次方,同理>>为右移运算符
第10题:矩形覆盖
题目:
我们可以用
2*1
的小矩形横着或者竖着去覆盖更大的矩形。请问用n
个2*1
的小矩形无重叠地覆盖一个2*n
的大矩形,总共有多少种方法?
解析
类似跳台阶的
动态规划
问题,考虑覆盖最后 可能的情况,可能是 之后竖着覆盖一个,有可能是 后横着覆盖两个,所以 ,另外, (竖着覆盖一个), (竖着2个,或横着2个).
class Solution {
public:
int rectCover(int number) {
if (number == 0)
return 0;
if (number == 1)
return 1;
if (number == 2)
return 2;
int f1 = 1, f2 = 2, ret;
for (int i = 3; i <= number; i++)
ret = f1 + f2, f1 = f2, f2 = ret;
return ret;
}
};
第11题:二进制数中1的个数
题目
输入一个整数,输出该数二进制表示中
1
的个数。其中负数用补码表示。
解析
- 思路1:先判断整数二进制最右边一位是不是1.接着把输入的整数右移一位,此时原来处于右边数第二位的移到最右边了,再判断是不是1(i.e.
n&1
).这样每次移动一位,直到整个整数变成0为止。如果n是正数,右移一位最左边补0,若是负数,右移之后最左边补1,会陷入死循环。思路1否决。
class Solution {
public:
int NumberOf1(int n) {
int ret = 0;
while (n>0)
{
if ((n&1) == 1)
ret++;
n = n >> 1;
}
return ret;
}
};
- 思路2:不右移n。首先n与1做与运算,判断n的最低位是不是1。然后把1左移一位,再与n做与运算,就能判断i的低次位是不是1。不断左移,就能不断判断n的每一位是不是1. 思路2正确。
class Solution {
public:
int NumberOf1(int n) {
int ret = 0;
uint flag = 1;
while (flag>=1)
{
if ((n&flag) > 0)
ret++;
flag = flag <<1;
}
return ret;
}
};
- 思路3.把一个整数减去1,再和原来的整数做与运算,会把该整数最右边一个1变成0。那么一个整数的二进制表示中有多少个1,就可进行多少次这样操作。如果没有1了,此操作结果即为0.
class Solution {
public:
int NumberOf1(int n) {
int ret = 0;
while (n>0)
{
ret++;
n = (n-1)&n;
}
return ret;
}
};
备注
此题考查
位运算
。
位逻辑运算符 : & (与),^ (异或), | (或),~ (取反). 移位运算符:<< (左移),>> (右移)。
&
运算通常用于二进制取位
操作,例如一个数 &1的结果就是取二进制的最末位。
^
运算通常用于对二进制的特定一位进行取反
操作,^ 运算的逆运算是它本身,也就是说两次异或同一个数最后结果不变,即(a ^ b) ^ b=a;
a<<b
表示把a转为二进制后左移b位(在后面添加 b个0),a<<b的值实际上就是a乘以2的b次方,通常认为a<<1比a*2更快,因为前者是更底层一些的操作
a>>b
表示二进制右移b位(去掉末b位),相当于a除以2的b次方(取整)。我们经常用>>1来代替 /2
第12题:数值的整数次方
题目
给定一个
double
类型的浮点数base
和int
类型的整数exponent
。求base的exponent次方。
解析
二分求解
。
计算时判断exp的正负
和奇偶
时间复杂度:
class Solution {
public:
double Power(double base, int exponent) {
//判断exponent的正负
bool f = exponent < 0;
// 如果exponent为0,返回1
if ((exponent = abs(exponent)) == 0)
return 1.0;
// 计算二分解
double ret = Power(base, exponent / 2);
// 根据奇偶判断
ret = exponent % 2 ? ret * ret * base : ret * ret;
//根据正负判断
return f ? 1.0 / ret : ret;
}
};