【问题标题】:Java Collections Logic / Over coding issueJava 集合逻辑/过度编码问题
【发布时间】:2010-10-23 01:36:29
【问题描述】:

下面是我被要求做的一个练习的实现(参见 cmets)。它有效,我发布它的原因是函数 checkMiracle 看起来应该包含在一个更小的代码循环中 - 我正在写出同样的东西加上十次。问题是,我似乎找不到更短的方法。那么我的问题是,有人可以指出我减少此清单中代码的任何方向,也许需要考虑一些使其更紧凑或“聪明”的编码方式。任何帮助表示赞赏。 (练习表在 JCF 上,所以他强迫我们使用集合来编写代码)

/*A 10-digit decimal number N is said to be miraculous if it contains each of the ten decimal digits, and if
the 2-digit number consisting of the first two (most significant, i.e. leftmost) digits of N is divisible by
2, the 3-digit number consisting of the first three digits of N is divisible by 3, and so on up to and including
that N itself is divisible by 10. Write a program to discover a miraculous number (there really is one).
Proceed by making a list of the ten decimal digits, and repeatedly shuffling them until you chance upon an
arrangement that constitutes a miraculous number.
(Note: Type long rather than int is needed for 10-digit decimal integers.) */

import java.util.*;

public class Miracle {

 static private long miracleNum = 0;

 static private ArrayList<Integer> listing = new ArrayList<Integer>();

 static String castValue = "";


 public static void main(String[] args) {

  for(int i = 0; i < 10; i++) listing.add(i); 

  Collections.shuffle(listing);

  while(listing.get(0)==0) Collections.shuffle(listing); //make sure the number doesnt start with zero

  while(!(checkMiracle(listing))) Collections.shuffle(listing);//keep changing it until we get a miracle number



  for(long l : listing) castValue += l;

  miracleNum = Long.parseLong(castValue);

  System.out.println("Miracle num: " + miracleNum);


 }


 static public boolean checkMiracle(ArrayList<Integer> l) {


  long checkValue = Long.parseLong("" + l.get(0) + l.get(1));

  if(checkValue %2 != 0) return false;


  checkValue = Long.parseLong("" + l.get(0) + l.get(1) + l.get(2));

  if(checkValue %3 != 0) return false;


  checkValue = Long.parseLong("" + l.get(0) + l.get(1) + l.get(2) + l.get(3));

  if(checkValue %4 !=0) return false;


  checkValue = Long.parseLong("" + l.get(0) + l.get(1) + l.get(2) + l.get(3) + l.get(4));

  if(checkValue %5 !=0) return false;


  checkValue = Long.parseLong("" + l.get(0) + l.get(1) + l.get(2) + l.get(3) + l.get(4) + l.get(5));

  if(checkValue %6 !=0) return false;


  checkValue = Long.parseLong("" + l.get(0) + l.get(1) + l.get(2) + l.get(3) + l.get(4) + l.get(5) + l.get(6));

  if(checkValue %7 !=0) return false;


  checkValue = Long.parseLong("" + l.get(0) + l.get(1) + l.get(2) + l.get(3) + l.get(4) + l.get(5) + l.get(6) + l.get(7));

  if(checkValue %8 !=0) return false;


  checkValue = Long.parseLong("" + l.get(0) + l.get(1) + l.get(2) + l.get(3) + l.get(4) + l.get(5) + l.get(6) + l.get(7)+ l.get(8));

  if(checkValue %9 !=0) return false;


  checkValue = Long.parseLong("" + l.get(0) + l.get(1) + l.get(2) + l.get(3) + l.get(4) + l.get(5) + l.get(6) + l.get(7)+ l.get(8) + l.get(9));

  if(checkValue %10 !=0) return false;


  return true;


 }


}

【问题讨论】:

    标签: java collections logic


    【解决方案1】:

    你为什么不在一个循环中收集所有条件?然后,您可以将下一位数字添加到数字中以计算下一位。

    String partial = Long.parseLong(l.get(0));
    for (int i = 1; i < 10; ++i) {
      partial += Long.parseLong(l.get(i));
      if (Long.valueOf(partial) % (i+1) != 0)
        return false;
    }
    return true;
    

    此外,您可以通过使用求幂digit^(displacement) 来避免使用字符串。不得不通过使用集合来解决类似的问题看起来很怪诞……

    【讨论】:

    • +1 是唯一可以重复使用部分结果以避免嵌套循环的答案。
    • partial 可以变成一个 long 而不是每一步都使用指数作为 partial = partial * 10 + l.get(i)
    • 这不能编译(String partial = Long...),当我将其更改为编译时,逻辑关闭并给出错误答案。轻松愉快地检查,任何不是 38165472920 的答案都是错误的。
    • 我无法解决您的问题。我试图实现一个想法,您应该通过理解概念解决方案而不是书面解决方案来自行解决。我们不是来做你的工作,只是为了帮助:) 所以不要抱怨..
    • 无论如何我建议的方法是绝对正确的。但我不想浪费时间来适应字符串和集合的使用,而不是简单的数字。这是你的职责。
    【解决方案2】:

    也许使用循环删除一些代码重复:

    private static boolean checkMiracleN(List<Integer> l, int n){
       long sum = 0;
       for (int i=0; i<n; i++)
           sum = sum * 10 + l.get(i);
       return sum % n == 0;
    }
    
    private static boolean checkMiracle(ArrayList<Integer> l){
        for (int n=2; n<=10; n++)
           if (!checkMiracleN(l, n) 
              return false;
        return true;
    }
    

    【讨论】:

    • 算法上最好的是恕我直言,计算 2 * 3 * 5 * 7 (210),找到可以除以 210 的前 10 位数字,并按顺序搜索幻数,通过检查第一个,添加 210 并检查结果等等......
    【解决方案3】:

    使用辅助函数,以便您可以用循环替换重复的代码:

    static public String GetNumberString(ArrayList<Integer> l, int numDigits)
    {
        StringBuilder sb = new StringBuilder();
    
        for(int i = 0; i < numDigits; i++)
        {
            sb.Append(l.get(i));
        }
        return sb.ToString();
    }
    
    
    static public boolean checkMiracle(ArrayList<Integer> l) {
    
      long checkValue = 0;
    
      for (int i = 2; i < 10; i++)
      {
          checkValue = Long.parseLong(GetNumberString(l, i));
          if(checkValue % i != 0) return false;
      }
    }
    

    这仍然意味着您每次都在构建一个非常相似的字符串。一个改进是在每次循环迭代时递增地构建数字,而不是每次都重新构建它。

    【讨论】:

    • 这真的很酷,不幸的是它不起作用,我认为它被关闭了,它给出的答案不能被十整除,它在某一时刻给了我 3816547209。看看我能不能让它工作。
    • 这个想法是向您展示如何重构代码以消除重复,而不是提供保证完全没有错误的代码:-)
    【解决方案4】:

    你可以做几个捷径。 例如如果一个数字是偶数,它的最后一位必须是偶数

    如果 (l.get(1) % 2 == 0) 返回 false;

    如果一个数是十的倍数,它的最后一位必须是'0'

    如果 (l.get(9) == 0) 返回 false;

    如果一个数是 3 的倍数,如果它的数字是 3 的倍数,则和(9 相同)

    如果一个数是 5 的倍数,它的最后一位必须是 5 或 0。

    在大多数情况下,您不需要 * 或 %。您定义不需要创建字符串并对其进行解析。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多