每日一题算法:2020年6月13日 09:15:45 爬楼梯 climbStairs

2020年6月13日 09:15:45 爬楼梯 climbStairs

每日一题算法:2020年6月13日 09:15:45 爬楼梯 climbStairs_第1张图片

默认格式:

class Solution {
    public int climbStairs(int n) {

    }
}

解题思路:

1,找通式

这个应该能够找到通式才对。

1:1种

2:2种

3:3种

4:5种

5:8种

6:13种

7:21种

。。。找不到通式

2,递归

这么简单一道题要用递归真的很蠢诶。

递归的思想,给一个当前数,和一个终点数,然后进行两次递归,第一次是+1,第二次是+2.当当前值是结果值时,方法数+1,超过结果值时不加1.

在做的时候自己优化了一下,把+1变成了减1,把0作为了终点

int times=0;

    public int climbStairs(int n) {
        if(n-1==0){
            times++;
        }
        else if(n-1>0)
            climbStairs(n-1);
        if (n-2==0)
            times++;

        else if(n-1>0)
            climbStairs(n-2);
        return times;
    }

每日一题算法:2020年6月13日 09:15:45 爬楼梯 climbStairs_第2张图片
可惜,已经超限了,看来递归的这个思路是不对的。

3,找规律

虽然不能使用通式,但是在之前的那个找通式的过程中我发现了一个规律。虽然直接找种类数有点困难,但是我们可以对其进行分段。将其分为a个1和b个2的组合种类有多少种,比如5有3中类型,五个1,3个1一个2,两个2一个1,我们可以再通过公式计算,三个1和1个2能产生几种可能。

1个1和n个2 能产生n中可能

1个2和m个1 能产生m中可能

2个1和n个2 能产生 ((n-1)+1)*(n-1)/2

到这里其实就已经足够了,我们可以发现当我们求2个1和n个2 的组合时,可以将其分为1个1个n个2的组合,以及n-1个2和2个1的组合,而因为2 个1和n个2的组合我们实际上还是有公式可以计算的,所以我们只针对超过3的数进行分解。

将3个1和3个2分解成计算2个1和3个2的个数加上2个2和3个1的个数的和

核心思想,使用递归将n个1和m个b逐步分解成求2个1和m个b和2个b和n个1的总数和。

代码实现如下:

        public int stair(int num1,int num2){
            if (num1==2){
                return (num2+1)*(num2+2)/2;
            }
            else if (num2==2)
            {
                return (num1+1)*(num1+2)/2;
            }
            else
                return stair(num1-1,num2 )+stair(num1,num2-1);
        }

现在要考虑的是如何将一个正整数n分解成a个1和b个2

每日一题算法:2020年6月13日 09:15:45 爬楼梯 climbStairs_第3张图片

居然超过了100%比我想象得要好。

        public int climbStairs(int n) {
            int times=0;
            for (int num1=n,num2=0;num2<=n/2;){
                if (num1==0||num2==0)
                    times++;
                else if (num1==1)
                    times+=num1*(num2+1);
                else if (num2==1)
                    times+=num2*(num1+1);
                else
                    times+=stair(num1,num2 );

                num1-=2;
                num2++;
            }
            return times;
        }

        public int stair(int num1,int num2){
            if (num1==2){
                return (num2+1)*(num2+2)/2;
            }
            else if (num2==2)
            {
                return (num1+1)*(num1+2)/2;
            }
            else
                return stair(num1-1,num2 )+stair(num1,num2-1);
        }

看一下答案有什么巧妙的解法把。

    public int climbStairs(int n) {
        double sqrt5 = Math.sqrt(5);
        double fibn = Math.pow((1 + sqrt5) / 2, n + 1) - Math.pow((1 - sqrt5) / 2, n + 1);
        return (int)(fibn / sqrt5);
    }

答案居然有通项公式,而且只需要0ms,我凭什么拿100%[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
在这里插入图片描述

今天的题目告诉我一个道理,有些人天生就是比别人笨的,这是后天再怎么努力也无法弥补的事实。

上面列出来的公式这么简单我居然都没找到规律。

1:1种

2:2种

3:3种

4:5种

5:8种

6:13种

7:21种

1+2=3

2+3=5

3+5=8

每一级都是前面两级的和,而且就算规律没有找到,我也没能理解题目的思路,走台阶已经把题目形容地那么形象了,我却还把他理解成求所有组合可能的题目。

如果要走上第n级台阶,那么上一步必定是第n-2或者n-1级台阶,那么他在走着n-2和n-1级台阶的所有组合可能之和就是第n级台阶的组合数。这么简单的道理我做完了题目都没能明白。

每日一题算法:2020年6月13日 09:15:45 爬楼梯 climbStairs_第4张图片

如果理解了这一题要表达的内容,应该只需要3分钟就能把代码写出来

public int climbStairs(int n) {

    int p=1;
    int q=2;

    for (int i=2;i<n-1;i++){
        if (p>q)
            q=p+q;
        else
            p=p+q;
    }
    if (n==1)
        return 1;
    if (n==2)
        return 2;
        return p+q;
}

你可能感兴趣的:(每日一题算法)