题目

Square digit chains

A number chain is created by continuously adding the square of the digits in a number to form a new number until it has been seen before.

For example,

44 → 32 → 13 → 10 → 1 → 1
85 → 89 → 145 → 42 → 20 → 4 → 16 → 37 → 58 → 89

Therefore any chain that arrives at 1 or 89 will become stuck in an endless loop. What is most amazing is that EVERY starting number will eventually arrive at 1 or 89.

How many starting numbers below ten million will arrive at 89?


平方数字链

将一个数的所有数字的平方相加得到一个新的数,不断重复直到新的数已经出现过为止,这构成了一条数字链。

例如,

44 → 32 → 13 → 10 → 1 → 1
85 → 89 → 145 → 42 → 20 → 4 → 16 → 37 → 58 → 89

可见,任何一个到达1或89的数字链都会陷入无尽的循环。更令人惊奇的是,从任意数开始,最终都会到达1或89。

有多少个小于一千万的数最终会到达89?

解题

这个链式的之前好有有个题目和这个差不多的,直接暴力很简单。

JAVA

package Level3;

public class PE092{
    static void run(){
        int MAX = 10000000;
        int count = 0;
        for(int num=1;num<=MAX;num++){
            int numx = num;
            if(is89(numx))
                count +=1;
        }
        System.out.println(count);
    }
//    8581146
//    running time=1s973ms
    static boolean is89(int num){
        int next_num = num;
        while(true){
            if(next_num == 89) break;
            if(next_num == 1) break;
            next_num = nextNum(next_num);
        }
        if(next_num ==89)
            return true;
        return false;
    }
    static int nextNum(int num){
        int next_num = 0;
        while(num!=0){
            int tmp = num%10;
            next_num += tmp*tmp;
            num/=10;
        }
        return next_num;
    }

    
    public static void main(String[] args) {
        long t0 = System.currentTimeMillis();
        run();
        long t1 = System.currentTimeMillis();
        long t = t1 - t0;
        System.out.println("running time="+t/1000+"s"+t%1000+"ms");

    }
}

 Python运行时间比较长

# coding=gbk

import time as time 
from itertools import combinations  
def run():
    MAX = 10000000
    count = 0
    for num in range(1,MAX):
        if is89(num):
            count+=1
    print count 
 
# 8581146
# running time= 305.638000011 s   
def next_num(num):
    return sum([a*a for a in map(int ,str(num))])

def is89(num):
    while True:
        if num == 89 or num == 1:
            break
        num = next_num(num)
    if num == 89:
        return True 
    return False 

t0 = time.time()
run() 
t1 = time.time()
print "running time=",(t1-t0),"s"

            

85 → 89 → 145 → 42 → 20 → 4 → 16 → 37 → 58 → 89

题目给了一个这样的提示,只有我们知道中间的数,就一定能到89

最大值是9999999 ,nextnum = 9*9*7 = 567 ,可以定义一个568的数组来保存中间的计算结果能到达89的。

这里我只定义一个boolean数组Judge。先保存前一步的值numx, 若nextnum[numx] == 89 则,则Judge[numx] ==True

在以后我们可以先判断nextnum在Judge中是否是true,true就不用计算了。

当然如果定义一个矩阵,保存所有的计算中间值,这个比较复杂啊,对了,可以定义一个set,也很好判断是否存在。下面尝试一下。

下面run2() 是定义boolean数组的,run3()是定义两个set的。

定义boolean数组的  对所有的值是否都能判断? 这里就不知道了。所以才想起了定义set的

package Level3;

import java.util.TreeSet;

public class PE092{
    static void run3(){
        int MAX = 10000000;
        int count =0;
        TreeSet<Integer> path = new TreeSet<Integer>();
        TreeSet<Integer> judge = new TreeSet<Integer>();
        for(int num =2;num<MAX;num++){
            int numx = nextNum(num);
            if(path.contains(numx)){
                count +=1;
            }else{
                while(true){
                    judge.add(numx);
                    numx = nextNum(numx);
                    if(path.contains(numx) || numx==89){
                        path.addAll(judge);
                        judge.clear();
                        count +=1;
                        break;
                    }
                    if(numx == 1){
                        judge.clear();
                        break;
                    }
                }
            }
        }
        System.out.println(count);
    }
//    8581146
//    running time=0s953ms
    
    // 9*9*7 = 567 定义一个长度是567的数组保存之前计算过程中的值  
    // 若以89结束定义为true 以后认为是true就可以直接认为是89结束了
    static void run2(){
        int MAX = 10000000;
        int count = 0;
        boolean Judge[] = new boolean[568];
        for(int num =1;num<MAX;num++){
            // 求下一个数
            int numx = nextNum(num);
            // 下一个数是否计算过
            if(Judge[numx]){
                count+=1;
            }else{ 
                while(true){
                    // 继续求下一个数 
                    int tmp = nextNum(numx);
                    // 计算过或者 遇到89的时候把之前的数更行Judge[numx]  
                    if(Judge[tmp] || tmp==89){
                        count+=1;
                        Judge[numx] = true;
                        break;
                    }
                    if(tmp ==1) break;
                    numx = tmp;
                    
                }
            }
        }
        System.out.println(count);
    }
//    8581146
//    running time=0s944ms
    static void run(){
        int MAX = 10000000;
        int count = 0;
        for(int num=1;num<=MAX;num++){
            int numx = num;
            if(is89(numx))
                count +=1;
        }
        System.out.println(count);
    }
//    8581146
//    running time=1s973ms
    static boolean is89(int num){
        int next_num = num;
        while(true){
            if(next_num == 89) break;
            if(next_num == 1) break;
            next_num = nextNum(next_num);
        }
        if(next_num ==89)
            return true;
        return false;
    }
    static int nextNum(int num){
        int next_num = 0;
        while(num!=0){
            int tmp = num%10;
            next_num += tmp*tmp;
            num/=10;
        }
        return next_num;
    }

    
    public static void main(String[] args) {
        long t0 = System.currentTimeMillis();
        run2();
        long t1 = System.currentTimeMillis();
        long t = t1 - t0;
        System.out.println("running time="+t/1000+"s"+t%1000+"ms");

    }
}

Python

# coding=gbk

import time as time 
def run2():
    MAX = 10000000
    count = 0 
    path=[]
    judge=[]
    for num in range(1,MAX):
        numx = next_num(num)
        if numx in path:
            count +=1
        else:
            while True:
                judge.append(numx)
                numx = next_num(numx)
                if numx in path or numx == 89:
                    count+=1
                    path +=judge
                    judge=[]
                    break
                if numx ==1:
                    judge = []
                    break
    print count 
#     8581146
# running time= 165.453000069 s