蓝桥杯省赛----等差数列

等差数列 - 蓝桥云课 (lanqiao.cn)

题目描述

数学老师给小明出了一道等差数列求和的题目。但是粗心的小明忘记了一 部分的数列,只记得其中 有N 个整数。

现在给出这 N 个整数,小明想知道包含这 N 个整数的最短的等差数列有几项?

输入描述

输入的第一行包含一个整数N。

第二行包含 N 个整数A1​,A2​,⋅⋅⋅,AN​。(注意 A1​ ∼ AN​ 并不一定是按等差数列中的顺序给出)

其中,2≤N≤100000,,0≤Ai​≤1000 000 000。

输出描述

输出一个整数表示答案。

输入输出样例

示例

输入

5
2 6 4 10 20

输出

10

样例说明: 包含 2、6、4、10、20 的最短的等差数列是 2、4、6、8、10、12、14、16、 18、20。

解题思路

1.首先我们应该给定一个长度为N的数组, 由于VS编译器不支持变长数组,在这里我选择calloc一个长度为N的数组。

2.其次我们可以想到一个等差数组最短,那么它们的公差肯定是最大的,那么它们的最大公差,应该不大于两个相邻数之差的最小值。

例1

数组为2        5        11        20

相邻差      3        6        9

 那么最大公差就应该是3,即组成2 5 8 14 17 20

例2

数组为30        45        70        90

相邻差      15        25         20

 那么最大公差就应该是5,即组成30 35 40 45 50 55 60 65 70 75 80 85 90

这样就可以确定一个最大公差的范围。

3.接着再对所有的差值求它们的最大公因数,所得到的最大公因数就是该数组的最大公差。

解题

第一步

创建一个N长的数组,vs不支持变长数组,当然绝大部分的测试平台是支持的,这里也可以使用变长数组。

int n;
	scanf("%d", &n);
	int* pa = (int*)calloc(n, sizeof(int));//数列
	int i;
	perror("calloc1");
	for (i = 0; i < n; i++)
	{
		scanf("%d", &pa[i]);
	}

第二步

由于题目中给的条件是数组并非按照等差顺序,这里我们应该先对数组排序一下,因为最后计算等差数组元素个数的时候运用an=a0+d*(k-1)

在这里我用了快排qsort函数,因为oj里面冒泡的时间复杂度太高了,O(n^2)过不去检测。

int compare(const void* a, const void* b)
{
	return *(int*)a - *(int*)b;
}

//数列从小到大排序
	qsort(pa, n, sizeof(int), compare);
	//冒泡O(n2)时间复杂度太高
	/*for (i = 0; i < n; i++)
	{
		for (j = 0; j < n - i - 1; j++)
		{
			if (pa[j] > pa[j + 1])
			{
				temp = pa[j];
				pa[j] = pa[j + 1];
				pa[j + 1] = temp;
			}
		}
	}*/

第三步

计算两两之间的差值,并且把他们存到pb数组内,因为有n个数,相邻数之间最多只有n-1个差值。

int* pb = (int*)calloc(n - 1, sizeof(int));//两两之间的差值
	perror("calloc2");
	for (i = 0; i < n - 1; i++)
	{
		pb[i] = pa[i + 1] - pa[i];
	}

第四步

差值从小到大排一下,找到最小的差值,因为前面用到了快排,偷个懒直接得到最小的就是pb[0],也不用重新写循环。

//差值从小到大排序
	qsort(pb, n - 1, sizeof(int), compare);
	//冒泡O(n2)时间复杂度太高
	/*for (i = 0; i < n; i++)
	{
		for (j = 0; j < n - i - 1; j++)
		{
			if (pb[j] > pb[j + 1])
			{
				temp = pb[j];
				pb[j] = pb[j + 1];
				pb[j + 1] = temp;
			}
		}
	}*/

第五步

插值去重(可以省略)一开始觉得去一下重可以减一点复杂度,但是其实影响并不是很大。

//差值去重
	int l = 0;
	for (i = 0; i < n - 1; i++)
	{
		if (pb[i] != pb[i + 1])
		{
			pb[l] = pb[i];
			l++;
		}
	}

 第六步

计算数组的最大公差。

如果最小差值是0,那么就是个常数列,长度就是n;

如果不是0,那么求所有差值的最大公约数。

思路很简单就是让每个差值对1-pb[0]取余数,如果余数是0,那么就是这个差值的约数,反之则不是,所有差值的约数相加,如果都是0的话那么sum也是0,如果有一个不是0,则表示不是公约数

int min = pb[0];//最小差值,最大公差就在1-min之间
	int k = 0;
	int sum;
	//0,则就是最大公差
	if (pb[0] == 0)
	{
		k = n;
	}
	//不是0则计算最小公差
	else
	{
		do
		{
            //求最大公约数
			for (j = min; j >= 1; j--)
			{
				sum = 0;
				for (i = 1; i < l; i++)
				{
					sum = sum + pb[i] % j;
				}
				if (sum == 0)
				{
					break;
				}
			}
		} while (sum);
		k = 1 + (pa[n - 1] - pa[0]) / j;
	}

结束

 全题思路就是这样,代码有可以优化的地方大家可以在下面留言。

你可能感兴趣的:(蓝桥杯,职场和发展,算法,c语言)