题目描述
下面的图形是著名的杨辉三角形:
如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列: 1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1 ⋯
给定一个正整数 N,请你输出数列中第一次出现 N 是在第几个数?
输入描述
输入一个整数 N。
输出描述
输出一个整数代表答案。
输入输出样例
示例 1
输入:
6
输出:
13
评测用例规模与约定
对于 20% 的评测用例,1 ≤ N ≤ 10; 对于所有评测用例,1 ≤ N ≤ 1000000000。
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
解题思路:
这道题需要了解杨辉三角形的大概规律,从规律入手将问题进行简化,从而降低了算法的时间复杂度,若通过暴力求解则系统会显示时间超时。
对于杨辉三角形,仔细观察可以发现规律:
- 每一行的后半段都在该行的前半段出现过,故对于求解首次出现问题,可以不考虑每一行的后半段情况,只需考虑改行的前半段即可。
- 对于杨辉三角形上的每一个位置的值,若该位置为 (i , j),即行数和列数下标从 0 开始算起,该位置在第 i 行第 j 列,故该位置的值为 。
- 对于第 i 行来说,有效位置为 (i ,i / 2) 处开始往下。
本题中我们可以考虑使用一下方法进行求解:
- 对每一列来进行遍历,首先对于第一列来说(下标为 0),该位置上的每一位数字都是 1 ,故若用户输入的数字为 1 即可直接输出 1 为答案即可。
- 对于列数等于 2 的情况 (下标为 1),由于此列较为特殊,是一个行下标和值相同的一行,故该行中我们可以直接确定值为 N 的行数 (此时列数确定为第二列,下标为 1 ),故可直接计算该位置为第几。
- 对于列数大于等于 3 (下标为 2)的情况我们可以考虑建立一个类型为 double 的数组 (因为最大位数为十亿数量级),长度需要我们去计算,比方说对于第三列来说,当第 i 行第 3 列的数值大于等于 1000000000 时即可,此时的数组长度便可以作为我们所需构建数组的长度。至于怎么计算这个数组长度呢?我们首先可以通过计算器考虑是否长度为 50000 可以达到十亿级的数据,计算方法前面提过,就是杨辉三角形上任一位置的数值等于 ,故 i = 50000,此时 j 是确定的 2 ,代入计算得第 50000 行第 3 列的数值大于十亿级,故缩小 i 进行估算 (使用计算器进行计算速度很快,不到几秒可以确定某个位置上的数值为多少) ,直到 i 取值为44800 时该位置上的数值和十亿级数量级差不多,于是第三列的数组长度为 44800 ,然后建立一个循环,计算第三列从有效位置算起 (有效位置前面也有提过)每个位置对应的值为多少并与 N 做判断,若相等则计算此时的 (i,j) 对应的位置,并和前面第二列时的暂时最小下标作比较,若小于暂时最小下标则令最小下标为此时计算出来的值。对于列数为第四列来说,此时若想要数量级达到十亿的话,列数也就小很多了,对应的数组长度也小很多了 (读者可自行去计算,大概为 1850 即可),并做如上的相同操作,注意一些细节方面的问题。
可能有读者会怀疑这个方法,认为杨辉三角形不断写下去,每一列都会有数值,那考虑的列数也就考虑不尽,如何判断所需考虑的最大列值呢?其实仔细一想可以发现,当你的列数 j 不断增大的时候,有效位也在不断下移 (i 也在增大),此时有效位的数值也在成倍的增大,大概当 j 为 16 的时候,此时的有效位为 (32 ,16),可以计算该位置的值大概逼近十亿数量级,也就是说,当你所考虑的列数在增大的同时,该列所对应的有效位也在不断增大,所以大概当 j 为 16 的时候,有效位已经是十亿数量级了,故 列数大于 16 的情况可以不考虑 (因为该题目中测试数据最大为十亿数量级)。
该算法的Java代码实现如下:
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
static long firstAppearance(int N) {
long minIndex = 0;
int i, j, temp;
double molecular, denominator;//分子、分母
for (i = 0; i < N; i++) {
minIndex += (i + 1);
}
minIndex += 2;//最初默认该位置在下标为1的列数第一次出现,后续可以迭代否定该假设
/**
* 若第三列出现
*/
double[] thirdColumn = new double[44800];
j = 2;
for (i = 4; i < 44800; i++) {
molecular = 1;
denominator = 1;
for (int k = 1; k <= j; k++) {
denominator *= (j - k + 1);
molecular *= (i - k + 1);
}
thirdColumn[i] = molecular / denominator;
if (thirdColumn[i] == N) {
temp = 0;
for (j = 0; j < i; j++) {
temp += (j + 1);
}
temp += 3;
if (temp < minIndex) {
minIndex = temp;
}
break;
}
}
/**
* 第四列
*/
double[] forthColumn = new double[1850];
j = 3;
for (i = 6; i < 1850; i++) {
molecular = 1;
denominator = 1;
for (int k = 1; k <= j; k++) {
denominator *= (j - k + 1);
molecular *= (i - k + 1);
}
forthColumn[i] = molecular / denominator;
if (forthColumn[i] == N) {
temp = 0;
for (j = 0; j < i; j++) {
temp += (j + 1);
}
temp += 4;
if (temp < minIndex) {
minIndex = temp;
}
break;
}
}
/**
* 第五列
*/
double[] fifthColumn = new double[396];
j = 4;
for (i = 8; i < 396; i++) {
molecular = 1;
denominator = 1;
for (int k = 1; k <= j; k++) {
denominator *= (j - k + 1);
molecular *= (i - k + 1);
}
fifthColumn[i] = molecular / denominator;
if (fifthColumn[i] == N) {
temp = 0;
for (j = 0; j < i; j++) {
temp += (j + 1);
}
temp += 5;
if (temp < minIndex) {
minIndex = temp;
}
break;
}
}
/**
* 第六列
*/
double[] sixthColumn = new double[167];
j = 5;
for (i = 10; i < 167; i++) {
molecular = 1;
denominator = 1;
for (int k = 1; k <= j; k++) {
denominator *= (j - k + 1);
molecular *= (i - k + 1);
}
fifthColumn[i] = molecular / denominator;
if (fifthColumn[i] == N) {
temp = 0;
for (j = 0; j < i; j++) {
temp += (j + 1);
}
temp += 6;
if (temp < minIndex) {
minIndex = temp;
}
break;
}
}
/**
* 第七列
*/
double[] seventhColumn = new double[98];
j = 6;
for (i = 12; i < 98; i++) {
molecular = 1;
denominator = 1;
for (int k = 1; k <= j; k++) {
denominator *= (j - k + 1);
molecular *= (i - k + 1);
}
fifthColumn[i] = molecular / denominator;
if (fifthColumn[i] == N) {
temp = 0;
for (j = 0; j < i; j++) {
temp += (j + 1);
}
temp += 7;
if (temp < minIndex) {
minIndex = temp;
}
break;
}
}
/**
* 第八列
*/
double[] eighthColumn = new double[69];
j = 7;
for (i = 14; i < 69; i++) {
molecular = 1;
denominator = 1;
for (int k = 1; k <= j; k++) {
denominator *= (j - k + 1);
molecular *= (i - k + 1);
}
fifthColumn[i] = molecular / denominator;
if (fifthColumn[i] == N) {
temp = 0;
for (j = 0; j < i; j++) {
temp += (j + 1);
}
temp += 8;
if (temp < minIndex) {
minIndex = temp;
}
break;
}
}
/**
* 第九列
*/
double[] ninthColumn = new double[53];
j = 8;
for (i = 16; i < 53; i++) {
molecular = 1;
denominator = 1;
for (int k = 1; k <= j; k++) {
denominator *= (j - k + 1);
molecular *= (i - k + 1);
}
fifthColumn[i] = molecular / denominator;
if (fifthColumn[i] == N) {
temp = 0;
for (j = 0; j < i; j++) {
temp += (j + 1);
}
temp += 9;
if (temp < minIndex) {
minIndex = temp;
}
break;
}
}
/**
* 第十列
*/
double[] tenthColumn = new double[46];
j = 9;
for (i = 18; i < 46; i++) {
molecular = 1;
denominator = 1;
for (int k = 1; k <= j; k++) {
denominator *= (j - k + 1);
molecular *= (i - k + 1);
}
fifthColumn[i] = molecular / denominator;
if (fifthColumn[i] == N) {
temp = 0;
for (j = 0; j < i; j++) {
temp += (j + 1);
}
temp += 10;
if (temp < minIndex) {
minIndex = temp;
}
break;
}
}
/**
* 第十一列
*/
double[] eleventhColumn = new double[41];
j = 10;
for (i = 20; i < 41; i++) {
molecular = 1;
denominator = 1;
for (int k = 1; k <= j; k++) {
denominator *= (j - k + 1);
molecular *= (i - k + 1);
}
fifthColumn[i] = molecular / denominator;
if (fifthColumn[i] == N) {
temp = 0;
for (j = 0; j < i; j++) {
temp += (j + 1);
}
temp += 11;
if (temp < minIndex) {
minIndex = temp;
}
break;
}
}
/**
* 第十二列
*/
double[] twelfthColumn = new double[38];
j = 11;
for (i = 22; i < 38; i++) {
molecular = 1;
denominator = 1;
for (int k = 1; k <= j; k++) {
denominator *= (j - k + 1);
molecular *= (i - k + 1);
}
fifthColumn[i] = molecular / denominator;
if (fifthColumn[i] == N) {
temp = 0;
for (j = 0; j < i; j++) {
temp += (j + 1);
}
temp += 12;
if (temp < minIndex) {
minIndex = temp;
}
break;
}
}
/**
* 第十三列
*/
double[] thirteenthColumn = new double[35];
j = 12;
for (i = 24; i < 35; i++) {
molecular = 1;
denominator = 1;
for (int k = 1; k <= j; k++) {
denominator *= (j - k + 1);
molecular *= (i - k + 1);
}
fifthColumn[i] = molecular / denominator;
if (fifthColumn[i] == N) {
temp = 0;
for (j = 0; j < i; j++) {
temp += (j + 1);
}
temp += 13;
if (temp < minIndex) {
minIndex = temp;
}
break;
}
}
/**
* 第十四列
*/
double[] fourteenthColumn = new double[33];
j = 13;
for (i = 26; i < 33; i++) {
molecular = 1;
denominator = 1;
for (int k = 1; k <= j; k++) {
denominator *= (j - k + 1);
molecular *= (i - k + 1);
}
fifthColumn[i] = molecular / denominator;
if (fifthColumn[i] == N) {
temp = 0;
for (j = 0; j < i; j++) {
temp += (j + 1);
}
temp += 14;
if (temp < minIndex) {
minIndex = temp;
}
break;
}
}
/**
* 第十五列
*/
double[] fifteenthColumn = new double[31];
j = 14;
for (i = 28; i < 31; i++) {
molecular = 1;
denominator = 1;
for (int k = 1; k <= j; k++) {
denominator *= (j - k + 1);
molecular *= (i - k + 1);
}
fifthColumn[i] = molecular / denominator;
if (fifthColumn[i] == N) {
temp = 0;
for (j = 0; j < i; j++) {
temp += (j + 1);
}
temp += 15;
if (temp < minIndex) {
minIndex = temp;
}
break;
}
}
return minIndex;
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int N = scan.nextInt();
if (N == 1) {
System.out.println(1);
}else {
System.out.println(firstAppearance(N));
}
scan.close();
}
}
可以发现该算法较为繁琐,代码有着大量的冗余,但是这并不影响通过蓝桥杯的测评系统,故至于实现代码简洁性的工作,读者有兴趣可以自行实现。