题目链接:https://projecteuler.net/problem=23
题目:题目如下:如果一个数的所有真因子之和等于这个数,那么这个数被称为完全数。例如,28的所有真因子之和为1 + 2 + 4 + 7 + 14 = 28,所以28是一个完全数。
如果一个数的所有真因子之和小于这个数,称其为不足数,如果大于这个数,称其为过剩数。
12是最小的过剩数,1 + 2 + 3 + 4 + 6 = 16。因此最小的能够写成两个过剩数之和的数字是24。经过分析,可以证明所有大于28123的数字都可以被写成两个过剩数之和。但是这个上界并不能被进一步缩小,即使我们知道最大的不能表示为两个过剩数之和的数字要比这个上界小。
找出所有不能表示为两个过剩数之和的正整数之和。
用了两种方法:
第一种是自己写好好久,最后发现一个很小的错误,使结果不对。
第二种看到网有用Python写的,改写成java的。
这个题目最重要的就是在找过剩数的时候会出现重读的问题,第一种是用HashSet解决的,第二种用的标记法解决这个问题。
第一种时间很长:2s130ms,第二种:1s53ms
solve():
1.先找出过剩数
2.求任意两个过剩数之和是否小于28124,<=28123的用HashSet保存下来,HashSet不能保存重复的元素
3.1-28123的和减去HashSet里面元素的和
solve2():
1.先定义两个数字a,b。a内元素是过剩数。b是1-28123
2.也是任意两个过剩数的和<=28123 的话,对于b的位置元素变为0.下面的第二个for循环从i开始,可以减少一半的不必要循环。要特别说明下。
for(int i=1;i<count;i++){for(int j=i;j<count;++j){int temp=arr[i]+arr[j];if(temp<=28123){b[temp]=0;}}}
3.b中元素的和就是结果
package projecteuler21to30;import java.util.Date;
import java.util.HashSet;class level23{
void solve2(){int[] arr=new int [28124];int[] b= new int[28124];for(int i=1;i<28124;i++){b[i]=i;}int count=1;for(int i=1;i<28124;++i){int s=getSum(i);if(s>i){arr[count]=i;count++;}}for(int i=1;i<count;i++){for(int j=i;j<count;++j){int temp=arr[i]+arr[j];if(temp<=28123){b[temp]=0;}}}int sum=0;for(int i=1;i<28124;++i){sum+=b[i];}System.out.println(sum);//1s53ms}void solve(){long sum=0;HashSet<Integer> al=new HashSet<Integer>();for(int i=1;i<28124;++i){int s=deficientNum(i);if(s!=-1) {al.add(i);}}Object[] array=al.toArray();HashSet hs=new HashSet();for(int j=0;j<array.length;++j){for(int k=j;k<array.length;++k){int temp=(Integer)array[j]+(Integer)array[k];if(temp<=28123){
//有重复的hs.add(temp);}}}sum=0;for(Object obj:hs){int res=(Integer)obj;sum+=res;}int tempsum=0;for(int i=1;i<=28123;i++)tempsum+=i;System.out.println((tempsum-sum));//4179871 2s130ms}int getSum(int num){int sum=0;for(int i=1;i<num/2+1;++i){if(num%i==0){sum+=i;}}return sum;}int deficientNum (int num){int sum=0;for(int i=1;i<=num/2;i++){if(num%i==0) sum+=i;}if(sum>num) return num;return -1;}}
public class Problem23 {
public static void main(String[] args){Date beginTime=new Date();new level23().solve2();//4179871Date endTime=new Date();long Time = endTime.getTime()-beginTime.getTime();System.out.println("Time:"+Time/1000+"秒"+Time%1000+"毫秒");}
}