去年的蓝桥杯H题杨辉三角形你满分了吗?

直接看题:

其实和普通的杨辉三角一样,唯一不一样的是,这次变成了求某个数所在的位置,可是为什么那么多人无法得到分,或者只能骗分呢?简单说就是方法不对。

解析:

先看一下下面这个,是杨辉三角的前8行数据

1    0    0    0    0    0  0  0  0  0  0  0
1    1    0    0    0    0  0  0  0  0  0  0
1    2    1    0    0    0  0  0  0  0  0  0
1    3    3    1    0    0  0  0  0  0  0  0  0  0  0
1    4    6    4    1    0  0  0  0  0  0  0  0  0  0  0
1    5    10  10  5    1  0  0  0  0  0  0  0  0  0  0  0
1    6    15  20  15  6  1  0  0  0  0  0  0  0  0  0  0  0
1    7    21  35  21  7  1  0  0  0  0  0  0  0  0  0  0  0

第一列:永远为1

第二列:从0开始的递增序列

第三列:1+2+3....的累加序列

分析:

第一列始终为1,不管;

第二列为n-1,也不管(你总不可能定义一个十亿行的数组对吧?)

那来看第三列,第三列的值为下图所示:

0
0+0
0+0+1
0+0+1+2
0+0+1+2+3
0+0+1+2+3+4
0+0+1+2+3+4+5
..........
0+0+1+2+........+n

那么,如果说第三列的数值大于10亿了,并且在这之前都没有出现过所需要的值,那么我们是不是就可以判定这个值在第n+1行的第二位数?

那么就有了一个公式:(1+n)*n/2+2;而如果你直接用这个公式的话,可以得50分:

对于这题,50%好像不算太少了,好多网上题解只有30%/40%,而代码确实一大串

有了这50%的基础,那么我们就可以知道,剩下 的数值都是在第三列大于十亿之前可以求得的

那么就得判断一下前面到底有多少行数据需要获取:

而0+0+1+2+...+n>1e9,把前面两个0去除就是一个等差数列,且差值为1

可以求得n为44721;那么加上前面的两个0,就是第44723行数据

为了防止不确定因素,我们给它定为44725可以吧?

那问题又来了,定义一个44725行的二维数组, arr[44725][44725]?

这当然不可能,这样的话会内存超限,那接下来该怎么写呢?

我们可以用记忆化的方法去写着一个代码

每一行都有n个值,第一行1个,第二行2个,第n行n个,那最大行数44725就有44725个数值

借助一下上面的图:

1    0    0    0    0    0  0  0  0  0  0  0
1    1    0    0    0    0  0  0  0  0  0  0
1    2    1    0    0    0  0  0  0  0  0  0
1    3    3    1    0    0  0  0  0  0  0  0  0  0  0
1    4    6    4    1    0  0  0  0  0  0  0  0  0  0  0
1    5    10  10  5    1  0  0  0  0  0  0  0  0  0  0  0
1    6    15  20  15  6  1  0  0  0  0  0  0  0  0  0  0  0
1    7    21  35  21  7  1  0  0  0  0  0  0  0  0  0  0  0

第二行的第二列的1,是不是等于第一行的第二列的0+第一行第一列的1?

第三行第三列的1,等于第二行第三列的0+第二行第二列的1;

第三行第二列的2等于第二行第二列的1+第二行第一列的1;

这样子是不是就是要用到一个二维数组了?

那我们换一个看法,第一行数据怎么变成第二行数据?

arr[1]=1;arr[2]=0;arr[3].......arr[n]=0;

第二列的值初始为0吧?第二行第二列的数是上面两个数的和对吧?

那就是0+arr[1]对吧,也就是arr【2】=0+arr【1】;

那arr【2】初始状态为0,是不是就可以写成:arr【2】=arr【2】+arr【1】?

那从第一行变成第二行后,怎么变成第三行?

arr【3】=arr【3】+arr【2】;

arr【2】=arr【2】+arr【1】;这样是不是就完事了?

那第n行:arr【n】=arr【n】+arr【n-1】;arr【n-1】=arr【n-1】+arr【n-2】........;

那么定义一个数组 ,n从1到44725运行一次判断,是否存在就可以获得正确解

确实,这样就是一个满分答案,但是你们自己看一下cpu运行时间

 接下来讲的,有兴趣就看看,没兴趣直接拉底有代码

我们知道,杨辉三角是上行两数和,那么我们现在要看看它什么时候会出现超过十亿的值?

看上图我们可以知道 当运算到第三十四行的时候,就已经出现了大于10亿的值,位置是第16位,所以我们可以求得,每一次运算最多运算16个数值(杨辉三角对称原因,只求一半)

所以我们就可以求得,第n行最多要求的值为n-16------n这16个值

所以更改了代码

下面是代码块,分为两个,前面的是普通,cup长,一个是优化,费脑

代码一:

import java.util.Scanner;
public class 杨辉三角 {
    public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
        long n = scan.nextLong();//输入值,查找
        long[] arr =new long[44725];
        arr[0]=1;
        long k=1L;//k来定义位置
        if (n == 1) {
            System.out.println(1);
            return;
        }
        for (int i = 1;i<44725; i++) {
            for (int j = i; j>=1; j--) {
                arr[j] += arr[j - 1];//换行后,进行运算,减少内存
                if (arr[j] == n) {
                    System.out.println(k + i-j + 1);
                    return;//如果找到了就结束
                }
            }
            k+=(i+1);//每一行有i个值
        }
        System.out.println(((1 + n) * n / 2) + 2);
    }
}

代码二:

import java.util.Scanner;
public class 杨辉三角 {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        long n = scan.nextLong();
        long[] arr =new long[44725];
        arr[0]=1;
        long k=1L;
        if (n == 1) {
            System.out.println(1);
            return;
        }
        for (int i = 1;i<44725; i++) {
            for (int j = i; j>=i-16&&j>=1; j--) {
                arr[j] += arr[j - 1];
                if (arr[j] == n) {
                    System.out.println(k + i-j + 1);
                    return;
                }
            }
            k+=(i+1);
        }
        System.out.println(((1 + n) * n / 2) + 2);
    }
}

  • 42
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 25
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值