庞果英雄会——杨辉三角的变形

题目详情

         1

     1   1  1

  1  2   3  2  1

1 3  6   7  6  3  1

以上三角形的数阵,第一行只有一个数1, 以下每行的每个数,是恰好是它上面的数,左上的数和右上数等3个数之和(如果不存在某个数,认为该数就是0)。

求第n行第一个偶数出现的位置。如果没有偶数,则输出-1。例如输入3,则输出2,输入4则输出3。

输入n(n <= 1000000000)

函数头部:

C/C++:

    int run(int n);

java:

public solution {

    public static int run(int n);

}

分析

首先想到的是最简单直接的方法硬算,考虑到三角形的对称性,可以只计算一半得出结果。
将数据 存放在 按照如下图所示的数组中:

第n行只需要第n-1行的计算结果,且,k<n时,有arr[n][k] = arr[n-1][k] + arr[n-1][k - 1] + arr[n][k - 2],当k==n时,有arr[n][k] = arr[n-1][k - 1] + 2 * arr[n][k - 2]。由于问题只需要计算出第一个偶数的位置,所以可以将上式中的加法,换为异或可以加快速度。
#define N	6
//int arr[1000000005];
unsigned char arr1[N + 5];
unsigned char arr2[N + 5];

int run(int n)
{
	if(n == 1 || n == 2)//当n为1,2时,都是-1
		return -1;

	//利用两个指针,交替保存计算结果,这样可以避免使用N*N的数组
	unsigned char *parr_old = arr1;
	unsigned char *parr_cur = arr2;
	unsigned char *ptmp;
	int index;

	arr1[1] = 1;
	arr2[1] = 1;
	for(int i = 2; i < n; ++i)//计算从2到n-1的三角内值
	{
		index = i > N ? N : i;
		for(int j = 2; j < index; ++j)
		{
			//由于只要得出奇偶结果,只利用每个数的最后一位即可,可以利用异或运算更快
			//每个数只与其上一层中的第j个和第j-1,第j-2个数有关
			parr_cur[j] = parr_old[j] ^ parr_old[j - 1] ^ parr_old[j - 2];
		}
		if(i < N)//三角形的中线上的数,与j-1,j-2和j有关,但是j-2与j是一样的,异或为0,所以只需要j-1
			parr_cur[i] = parr_old[i - 1];

		ptmp = parr_old;
		parr_old = parr_cur;
		parr_cur = ptmp;
	}

	for(int j = 2; j <= index; ++j)//找到第一个偶数
	{
		parr_cur[j] = parr_old[j] ^ parr_old[j - 1] ^ parr_old[j - 2];
		if((parr_cur[j] & 0x01) == 0)
		{
			return j;
		}
	}

	return -1;
}
但是仔细读题后发现 n <= 1000000000的,上面的算法时间复杂度是O(n^2),一定会超时。
不过可以利用上面的方法分析结果,找出规律。
n为3-50内的数时计算结果为:

可以看出,结果只有2,3,4三种数字,当n为奇数时,都是3,n为偶数时结果只与n的第二位有关,即(n>>1&0x01) +3.所以可以得到代码:
int run(int n)
{
	if(n < 3)
	{
		return -1;
	}

	if(n & 0x01 == 1)
	{
		return 2;
	}
	return ((n >> 1) & 0x01) + 3;
}
这个时间复杂度为O(1)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值