1爬楼梯算法(斐波那契数列)
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
- 1 阶 + 1 阶
- 2 阶
示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
- 1 阶 + 1 阶 + 1 阶
- 1 阶 + 2 阶
- 2 阶 + 1 阶
示例 3:
输入: 4
输出: 5
解释: 有五种方法可以爬到楼顶。
- 1 阶 + 1 阶 + 1 阶+ 1 阶
- 1 阶 + 1 阶 + 2 阶
- 1 阶 + 2 阶 + 1 阶
- 2 阶 + 1 阶 + 1 阶
- 2 阶 + 2 阶
很明显,这是一个斐波那契数列,即a[n] = a[n-2] + a[n-1]。n的结果都是由前两个值相加得到的。
闭包实现
假如不考虑空间复杂度的问题,可以将每次结果都缓存起来,这样下次计算就可以省略很多计算步骤。
具体代码实现如下
/**
* @param {number} n
* @return {number}
*/
var climbStairs = function(n) {
let result = {
0: 1,
1: 1
};
function getData(n){
if(!result[n]){
result[n] = getData(n-1) + getData(n-2);//缓存结果
}
return result[n]
}
return getData(n)
}
时间复杂度为O(n),空间复杂度也为O(n)。优点是结果可以被缓存,下次计算的时候性能较好,对于只需进行一次求值的需求来说没啥区别。缺点是比较占内存。
代码如下:
/**
* @param {number} n
* @return {number}
*/
var climbStairs = function(n) {
let result = {
0: 1,
1: 1
};
function getData(n){
if(!result[n]){
result[n] = getData(n-1) + getData(n-2);
}
return result[n]
}
return getData(n)
}
遍历实现
/**
* @param {number} n
* @return {number}
*/
var climbStairs = function(n){
if (n == 0)
return 0;
else if (n == 1)
return 1;
else{
let one = 0,
two = 1,
i = 0,
ret;
for(; i < n; i++){
ret = one + two;
one = two;
two = ret;
}
return ret;
}
};
思路是,传入n的值,从0开始计算0-n的值,每次计算的时候将n-1和n-2的值都存起来给下次计算使用。
优点:时间复杂度O(n),空间复杂度为O(1),比用闭包思路节省了不少内存空间
2 帽子颜色
A、B、C、D四个人分别带着一顶帽子。共两顶黑帽子,两顶白帽子。其中D和A、B、C三个隔了一堵不透明的墙。A可以看到B、C帽子的颜色。B可以看到C帽子的颜色。只要能判断自己的帽子颜色,就可以立刻说出来。他们四人沉默了几分钟,这时候一个人说到,他知道自己帽子的颜色是什么了,请问这个人是谁?
解题
答案:B。
解释:因为场上一共只有 2 黑 2 白。所以:
- 如果有一个人看到了 2 个黑帽子,那么他就可以据此推断出自己是白帽子;
- 如果他看到了 2 个白帽子,那么他就可以据此推断出自己是黑帽子。\
因为场上只有 A 能够看到 2 个人的帽子,而他没有说话,说明他看到的是一黑一白的帽子。
因为 A 没有说话,所以 B 和 C 知道了他们俩是一黑一白的帽子。\
又因为 B 能看到 C 的帽子颜色,所以 B 就可以知道自己的颜色刚好就是与 C 相反的颜色。
3 老王卖鞋
题目:
老王卖鞋,一双进价30元,老王赔本卖,只卖20元。有个骗子来买,给老王50元假钞。老王未能识别,又没有零钱,把这假钞拿到隔壁铺子的老李换了50元零钱,回来找了骗子30。隔壁很快发现问题,拿假钞来换,老王只好把自己的家底真钞50元换给隔壁。问老王损失了多少钱?
答案:60 元。
解释:这道题容易把人绕晕,我想了一个办法理清楚,就是把老王收到的和拿出去的钱财分开单列,最后收到的和付出的相抵,就是正确答案。\
那么老王收到的东西有:
- 一张假钞(价值0)
- 找老李换来的 50 元零钱
老王付出的东西有:
- 一双鞋。值 30 元。
- 找给骗子的 30 元零钱。
- 退给老李的 50 元钱。
所以最终老王亏了 30 + 30 + 50 - 50 = 60 元。
4 赛马
题目:25匹马,5条跑道。要选出最快的前三名,最少要跑几次?
答案:7 次。
解释:先把 25 匹马分成 5 组,我们把这 5 组叫做 A、B、C、D、E 组。这 5 组先各进行一次比赛。这样已经有 5 个小组第一了。
然后 5 个小组第一再比一次,这样就找出了第一名,我们把第一名所在的组叫 A 组,第二名所在的组叫 B 组,第三名所在组叫 C 组。
剩下我们需要判断 A2, A3, B1, B2, C1 这几个到底谁更快。这样就可以找出最快的三匹马。
之所以这样比,是因为前三名有可能有以下四种情况:
- 前三名都直接在一个小组内。
- 前三名分别在三个不同小组内。
- 前三名前两名一组,第三名一组。
- 前三名第一名在一组,另两名在一组。
比较 A2, A3, B1, B2, C1 就可以把以上情况都考虑到。
衍生问题:如果我们要找出前五名,最少要比几次?
5 抛硬币
题目:有23枚硬币在桌上,10枚正面朝上。蒙住你的眼睛(你无法分清正反),如何分成两组,让两组硬币正面朝上的一样多?
答案:把硬币分成两组,一组 10 个,另一组 13 个。然后把 10 个的那组翻面即可。
解释:因为我们是随机分成两组,所以 10 个那组( 我们叫 A 组),我们假设有 X 个硬币朝上。那么就有 10 - X 个硬币朝下。
另一组(我们叫 B 组),因为 23 个硬币一共只有 10 枚朝上,所以那组有 10 - X 个朝上,剩下的朝下。
我们将 A 组全部翻面,所以朝上朝下个数交换:朝上的变成 10 - X 个,朝下的变成 X 个。
所以 A 组有 10 - X 个朝上,与 B 组朝上的个数相同。
6 水杯
题目:有三个杯子,容量各是10升、7升、3升。把10升的装满水。问:不用别的测量,怎样能将 10 升水分成两个 5 升。
答案:
- 先往 3 升杯子里面倒满水,然后把水从 3 升杯子中转入 7 升杯子中。
- 以上步骤重复 3 次。到第三次的时候,7 升杯子装满了,3升杯子中还剩 2 升水。
- 这个时候把 7 升杯子的水倒回 10 升杯子。
- 把 3 升杯子剩的 2 升水倒到 7 升杯子。
- 最后再倒满 3 升杯子,然后把 3 升杯子的水倒到 7 升杯子。
- 此时,10 升杯子和 7 升杯子里,各有 5 升水。