数据结构和算法——复杂度为O(n)的1~n因数之和

复杂度为O(n)的1~n因数之和

目录
一、题目描述
二、传统写法
三、优化分析
四、代码演示


一、题目描述

题目: 输入一个数字n,求出这个数从1~n的所有因数之和

输入样例:
		12
输出样例:
		87





二、传统写法

所谓传统写法就暴力枚举,将每一个数字都提出所有的因子,然后进行相加统计,获得最终结果,方式如下:

int function(const int n)
{
	long long sum = 0;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= i; j++)
		{
			if (i%j == 0)sum += j;
		}
	}
	return sum;
}

这种算法的复杂度是很高的,所用的时间复杂度为O(n2)。所以就出现了下面这种优化的方案:

int function(const int n)
{
	long long sum = 0;
	for (int i = 1; i <= n; i++)  // 时间复杂度为:O(n)
	{
		for (int j = 1; j * j <= i; j++) // 时间复杂度为:O(根号n)
		{
			if (i % j == 0)
			{
				sum += j;
				if (j * j == i)continue; //break和continue都一样
				sum += i / j;
			}
		}
	}
	return sum;
}

这种优化的灵感是来自当 i*j==n时,相当于找到了两个因子,所以这里选择开方的方式判断,时间复杂度为0(n根号n),对比前一个算法来说节省了不少时间。不过复杂度还是很大,当n<=107时,计算时间将会超过1秒。





二、优化分析

比起暴力的枚举不同,这个算法使用的是1~n中每个因子提供的次数所算出来的,我们假设n=6,如下图:

数据结构和算法——复杂度为O(n)的1~n因数之和_第1张图片
上面表格中,因子1在1~n中存在的数量是6,具体存在的数字是1 2 3 4 5 6;同样理解,因子2在1~n中存在的数量是3,具体存在的数字是2 4 6。我们知道各个因子出现的次数之后,将每因子次数加起来再统计,最终结果就是我们所需要的因数之和,公式为i*(n/i)。


公式i×(n/i)的由来: i即时因子从1~n的每个因子;(n/i)即是计算因子数量,需要注意这里若i=4时,为什么结果为1而不是浮点数,第一是两个整数计算后还是整数,第二是若是两个,则这里存在它的数字就是4 8,这超出了n的最大值。





二、代码演示

下面是优化后的解法:

int function(const int n)
{
	long long sum = 0;
	for (int i = 1; i <= n; i++)
	{
		sum += i * (n / i);
	} 
	return sum;
}

这种算法的时间复杂度是O(n),优化成了线性阶,当n<=109时,计算的时间也是很理想的。

初学小白,若有不足的地方还请大佬指正,谢谢!

你可能感兴趣的:(数据结构和算法,数据结构,图论,c++)