【问题标题】:Finding the smith number between given range查找给定范围之间的史密斯数
【发布时间】:2019-12-09 06:34:17
【问题描述】:

我会很快进入正题。基本上,史密斯数是: 合数,其数字之和是其素因数(不包括 1)的数字之和。 (素数被排除在外,因为它们很容易满足这个条件)。史密斯数的一个例子是野兽数 666=2·3·3·37,因为 6+6+6=2+3+3+(3+7)=18。

我尝试过的:

  1. 在 for 循环中,首先我得到当前数字的 (i) 位数的总和
  2. 在同一循环中,我尝试获取数字的素数位数的总和。
  3. 我已经做了另一种方法来检查将在 for 循环中处理的当前数字是否为素数,如果它的素数将被排除

但是我的代码似乎不起作用,你们能帮忙吗?

    public static void main(String[] args) {
        smithInrange(1, 50);
    }

    public static void smithInrange(int start_val, int end_val) {

        for (int i = start_val; i < end_val; i++) {
            if(!isPrime(i)) { //since we banned prime numbers from this process i don't include them 
            int for_digit_sum = i, digit = 0, digit_sum = 0, for_factor_purpose = i, smith_sum = 0;
            int first = 0, second = 0, last = 0;
            // System.out.println("current number is" + i);
            while (for_digit_sum > 0) { // in this while loop i get the sum of current number's digits

                digit = for_digit_sum % 10;
                digit_sum += digit;
                for_digit_sum /= 10;
            }
            // System.out.println("digit sum is"+digit_sum);

            while (for_factor_purpose % 2 == 0) { // i divide the current number to 2 until it became an odd number
                first += 2;
                for_factor_purpose /= 2;
            }
            // System.out.println("the first sum is " + first);
            for (int j = 3; j < Math.sqrt(for_factor_purpose); j += 2) {
                while (for_factor_purpose % j == 0) { // this while loop is for getting the digit sum of every prime
                                                        // factor that j has
                    int inner_digit = 0, inner_temp = j, inner_digit_sum = 0;
                    while (inner_temp > 0) {
                        inner_digit = inner_temp % 10;
                        second += inner_digit;
                        inner_temp /= 10;
                    }
                    // System.out.println("the second sum is " + second);
                    for_factor_purpose /= j;
                }
            }
            int last_temp = for_factor_purpose, last_digit = 0, last_digit_sum = 0;
            if (for_factor_purpose > 2) {
                while (last_temp > 0) {
                    last_digit = last_temp % 10;
                    last += last_digit;
                    last_temp /= 10;
                }
                // System.out.println("last is " + last);

            }
            smith_sum = first + second + last;
            // System.out.println("smith num is "+ smith_sum);
            // System.out.println(smith_sum);
            if (smith_sum == digit_sum) {
                System.out.println("the num founded is" + i);
            }
        }
        }
    }

    public static boolean isPrime(int i) {
        int sqrt = (int) Math.sqrt(i) + 1;
        for (int k = 2; k < sqrt; k++) {
            if (i % k == 0) {
                // number is perfectly divisible - no prime
                return false;
            }
        }
        return true;
    }

输出是: 成立的人数是4 成立的人数是9 成立的人数是22 成立的人数是25 成立的人数是27 成立的人数是49

这个范围(1 到 50)之间的史密斯数是: 4、22和27

编辑:我发现问题是: Math.sqrt(for_factor_purpose) 看来我应该给它加 1 来消除平方数。感谢你们,我从其他角度看到了解决方案。 继续编码!

【问题讨论】:

  • 使用调试器并尝试查找smithInrange(25, 26);(因为您已经知道 25 被错误地识别为 smith 数。)如果您这样做,您会发现您的算法用于查找 25 的质因数是错误的(提前终止)

标签: java


【解决方案1】:

打印史密斯数的主循环。

      for (int i = 3; i < 10000; i++) {
         if (isSmith(i)) {
            System.out.println(i + " is a Smith number.");
         }
      }

确定提供的数字是否为史密斯数字的测试方法。仅当最后一个素数的大小小于被测数时,素数列表才会增加。


   static boolean isSmith(int v) {
      int sum = 0;
      int save = v;

      int lastPrime = primes.get(primes.size() - 1);
      if (lastPrime < v) {
         genPrimes(v);
      }
      outer:
      for (int p : primes) {
         while (save > 1) {
            if (save % p != 0) {
               continue outer;
            }
            sum += sumOfDigits(p);
            save /= p;
         }
         break;
      }
      return sum == sumOfDigits(v) && !primes.contains(v);
   }

帮助方法对数字的数字求和。

   static int sumOfDigits(int i) {
      return String.valueOf(i).chars().map(c -> c - '0').sum();
   }

还有主生成器。它使用创建时的列表来确定给定的 数是素数。


   static List<Integer> primes = new ArrayList<>(List.of(2, 3));
   static void genPrimes(int max) {
      int next = primes.get(primes.size() - 1);
      outer:
      while (next <= max) {
         next += 2;
         for (int p : primes) {
            if (next % p == 0) {
               continue outer;
            }
            if (p * p > next) {
               break;
            }
         }
         primes.add(next);
      }
   }
}

【讨论】:

    【解决方案2】:

    我不想破坏答案,而只是一些更简单的代码 sn-ps, 让一切变得更简单,更易读。

    public boolean isSmith(int a) {
        if (a < 2) return false;
        int factor = findDivisor(a);
        if (factor == a) return false;
    
        int sum = digitSum(a);
        // loop:
            a /= factor;
            sum -= digitSum(factor);
        ...
    }
    
    boolean isPrime(int a){
        for(int i = 2; i*i <= a; i++) {
            if (a % i == 0) {
                return false;
            }
        }
        return true;
    }
    
    int findDivisor(int a){
        for(int i = 2; i*i <= a; i++) {
            if (a % i == 0) {
                return i;
            }
        }
        return a;
    }
    
    int digitSum(int a) {
       if (a < 10) {
           return a;
       }
       int digit = a % 10;
       int rest = a / 10;
       return digit + digitSum(rest); 
    }
    

    如您所见,整数除法 23 / 10 == 2 和模(余数)%: 23 % 10 == 3 可以简化事情。

    而不是 isPrime,查找因子更符合逻辑。实际上最好的解决方案是使用findDivisor,而是立即找到所有因子

        int factorsSum = 0;
        int factorsCount = 0;
        for(int i = 2; i*i <= a; i++) {
            while (a % i == 0) {
                factorsSum += digitSum(i);
                a /= i;
                factorsCount++;
            }
        }
    
        // The remaining factor >= sqrt(original a) must be a prime.
        // (It cannot contain smaller factors.)
        factorsSum += digitSum(a);
        factorsCount++;
    

    【讨论】:

    • 感谢您的贡献和您的建议:) 我刚刚开始编码,我想随着时间的推移我会变得更好。
    • 我认为您的 findFactors 方法不正确。由于它只上升到 a 的平方根,因此您缺少大于该平方根的因子。例如。 202 有两个质因数,2 和 101。但 202 的平方根
    • @WJS 好点。 我知道最后一个循环确实以a 的值结束,这是最后一个主要因素 AFAIK。我已将代码添加到答案中。本来我不想把所有的东西都拼出来,留下足够的需要脑力体操的东西。关于极限:直觉上最好让循环直到 i 我回答的主要动机是避免双重除法和 sqrt 之类的事情。高达i*i &lt;= a的动态适配
    【解决方案3】:

    这里是代码。如果您需要进一步的帮助,请告诉我。该代码非常自我解释,并且从您的代码中提取了一些不错的内容,但是如果您需要我解释它,请告诉我。

    简而言之,我创建了检查数字是否为 smith 数字的方法,然后检查范围内的每个 int。

    import java.util.*;
    public class MyClass {
        public static void main(String args[]) {
             System.out.println(smithInRange)
        }
        public int factor;
        public boolean smithInRange(int a, int b){
            for (int i=Math.min(a,b);i<=Math.max(a,b);i++) if(isSmith(i)) return true;
            return false;
        }
        public boolean isSmith(int a){
            if(a<2) return false;
            if(isPrime(a)) return false;
            int digits=0;
            int factors=0;
            String x=a+¨" ";
            for(int i=0;i<x.length()-1;i++) digits+= Integer.parseInt(x.substring(i,i+1));
            ArrayList<Integer> pF = new ArrayList<Integer>();
            pF.add(a);
            while(!aIsPrime(pF)){
                int num = pF.get(pF.size-1)
                pF.remove(pF.size()-1);
                pF.add(factor);
                pF.add(num/factor)
            }
            for(int i: pF){
                if((factors+"").length()==1)factors+= i;
                else{
                    String ss= i+" ";
                    int nums=0;
                    for(int j=0;j<ss.length()-1;j++){
                        nums+=Integer.parseInt(ss.substring(j,j+1));
                    }
                }
            }
            return (factors==digits);
        }
        public boolean isPrime(int a){
            for(int i=2;i<=(int)Math.sqrt(a),i++){
                String s = (double)a/(double)i+"";
                if(s.substring(s.length()-2).equals(".0")){
                    return false;
                    factor = i;
                }
            }
            return true;
        }
        public boolean aIsPrime(ArrayList<int> a){
            for(int i: a) if (!isPrime(a)) return false;
            return true;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      • 2016-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多