开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情
题目描述
下面的图形是著名的杨辉三角形:
如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列: 1,1,1,1,2,1,1,3,3,1,1,4,6,4,1,⋯
给定一个正整数 N,请你输出数列中第一次出现 N 是在第几个数?
输入输出样例
示例 1
输入
6
输出
13
评测用例规模与约定
对于 20%的评测用例,1≤N≤10; 对于所有评测用例,1≤N≤1000000000。
解题思路
常规的做法就是根据上一层计算出下一层,直到找到值为n的数。但是,看这道题的N的范围非常的大,这样找肯定会超时的。我们仔细观察不难发现杨辉三角是有一定规律的。
- 左右两边的值是对称的,在计算时只需要计算一半就可以。
- 每一行的第2个数是递增的
3. 最重要的一点,只要当前的值大于了目标值,那么目标值第一次出现出现的地方就在n+1行的第2个值。
知道了这三点,我们就可以通过模拟找到等于n的值,或者大于n的值。(注:前n项和公式:Sn=n*(a1+an)/2)
代码
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
long n = scan.nextLong();
if (n == 1) {
System.out.println(1);
return;
}
// 前n项和公示 Sn = n(a1+an)/2;
int col = 3; // 当前杨辉三角的行数
List<Long> list = new ArrayList<>(); // 存放每行的数据,因为每一行前一部分和后一部分数据相同,所以只需要存放一半
List<Long> list2 = new ArrayList<>(); // 用来暂存每行数据
list.add(1L);list.add(1L);
while (true) {
list2.add(1L); // 每一行都需要先添加一个1
for (int i = 1; i < list.size(); i++) {
long num = list.get(i - 1) + list.get(i);
if (num == n) { // 等于目标值
long ans = (col - 1) * (1 + col - 1) / 2 + i + 1; // 前n项和+i;
System.out.println(ans);
scan.close();
return;
}
if (num > n) { // num已经大于目标值
long ans = n * (1 + n) / 2 + 2;
System.out.println(ans);
scan.close();
return;
}
list2.add(num); // 当前数等于上一层数+上一层之前一个数
}
if ((col & 1) != 1) { // 偶数行要再加一个
list2.add(list2.get(list2.size() - 1));
}
list = list2;
list2 = new ArrayList<>();
col++;
}
}
}
注意
这里n的取值范围非常大,已经大于了2的31次方,需要使用long来接受,在计算杨辉三角时也需要使用long来计算。这里卡了我半天没找到错。