算法 — 杨辉三角形

题目描述

下面的图形是著名的杨辉三角形:

如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列: 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 列,故该位置的值为  \textrm{C}_{i}^{j}
  • 对于第 i 行来说,有效位置为 (i ,i / 2) 处开始往下。

        

        本题中我们可以考虑使用一下方法进行求解:

  • 对每一列来进行遍历,首先对于第一列来说(下标为 0),该位置上的每一位数字都是 1 ,故若用户输入的数字为 1 即可直接输出 1 为答案即可。
  • 对于列数等于 2 的情况 (下标为 1),由于此列较为特殊,是一个行下标和值相同的一行,故该行中我们可以直接确定值为 N 的行数 (此时列数确定为第二列,下标为 1 ),故可直接计算该位置为第几。
  • 对于列数大于等于 3 (下标为 2)的情况我们可以考虑建立一个类型为 double 的数组 (因为最大位数为十亿数量级),长度需要我们去计算,比方说对于第三列来说,当第 i 行第 3 列的数值大于等于 1000000000 时即可,此时的数组长度便可以作为我们所需构建数组的长度。至于怎么计算这个数组长度呢?我们首先可以通过计算器考虑是否长度为 50000 可以达到十亿级的数据,计算方法前面提过,就是杨辉三角形上任一位置的数值等于  \textrm{C}_{i}^{j},故 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();
	}
}

        可以发现该算法较为繁琐,代码有着大量的冗余,但是这并不影响通过蓝桥杯的测评系统,故至于实现代码简洁性的工作,读者有兴趣可以自行实现。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值