算法学习(五)求解500万以内的亲和数,连续数据映射为数组

题目描述:
求500万以内的所有亲和数,如果两个数a和b,a的所有真因数之和等于b,b的所有真因数之和等于a,则称a,b是一对亲和数。
真因数:除了本身以外的所有因数,
列如:220的真因数:1,2,4,5,10,11,20,22,44,55,110;
284的真因数:1,2,4,71,142.
220= 1+2+4+71+142 = sum[284]
284 = 1+2+4+5+10+11+20+22+44+55+110 = sum[220]
分析:
一个数的因数不超过它的一半,我们可以利用数组,把数作为数组下标,数组对应元素为真因数之和,然后遍历满足sum[sum[i]] = i的i,和sum[i]为一对亲和数。
首先初始化时,数组每一项都有一个1,因为1是所有数的真因数。从然后因数i从2开始到n/2,由于本身不是真因数,所以对应项从2i开始,3i,4i,5i….直到k*i>n,这些项都包含因数i。所有这些项sum[2i],sum[3i]….都要加上i。然后就可以开始遍历寻找满足亲和数条件的项。
i= 2时,sum[4]+=2,sum[6]+= 2;sum[8]+=2….
i = 3时,sum[6]+= 3;sum[9]+= 3;sum[12]+=3….
i = 4时,sum[8]+=4;sum[12] +=4…

/*************************************************************************
    > File Name: find_qinhe.c
    > Author: zxl
  > mail: 857317335@qq.com
    > Created Time: 2016年04月18日 星期一 20时36分58秒
 ************************************************************************/

#include<stdio.h>
#define SIZE 5000000
int main()
{
    static int sum[5000001];   //大数组声明为静态,放在静态存储区
    int i,j;
    for(i = 1;i<= SIZE;i++)
        sum[i] = 1;        //每一项都含有1
    for(i = 2;i+i<=SIZE;i++)  //遍历所有因数,
    {
        j = 2*i;
        while(j<=SIZE)  //对于因数2,循环n/2次,对于因数3,循环n/3次,总的次数为n(1/2 + 1/3+ 1/4 + 1/n/2),总的时间复杂度为O(N* log N + N)
        {
            sum[j] +=i;     //包含因数的项要加上因数
            j+=i;
        }
    }
    for(i = 220;i<=SIZE;i++)
    {
        if(sum[i]>i && sum[i] <=SIZE&& sum[sum[i]] == i)//使用sum[i] >i可以去掉重复的,比如sum[248] = 220
        {
            printf("%d,%d\n",i,sum[i]);
        }
    }
    return 0;
}

需要注意的时,大数组定义的地方,如果在函数内,分配空间都在堆栈上,堆栈是比较有限的,大的空间都是分配到静态存储区,可以放在全局或者在函数里面定义加上static。
顺便扯点别的,可编程内存分为:静态存储区,堆区和栈区
静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,它主要存放静态数据、全局数据和常量。
栈区:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率高,但是分配的内存 容量有限。
堆区:称动态内存分配,程序在运行的时候用malloc或new申请任意大小的内存,可以自己负责在适当的时候free或delete释放内存。动态内存的生存期可以由我们决定。

总结:连续数据的映射可以通过数组结构本身的特点替代,用来节约空间,这是数据结构的艺术,在大规模连续数据的回溯法处理上,通过转化为递推生成的方法,逆向思维操作,这是算法的艺术。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值