寻找给定整数的因数

12

我有一个类似这样的代码:

int f = 120;
for(int ff = 1; ff <= f; ff++){
    while (f % ff != 0){            
}

我的查找因子的循环有什么问题吗?我对于for和while语句的工作原理感到非常困惑,所以它们很可能是完全错误的。

在此之后,我该如何将变量分配给这些因子?


2
是的,有些问题-里面没有代码。你打算如何找到因子?你期望将它们存储在哪里? - duffymo
6
只是一点小建议:我不会使用“f”和“ff”,因为这样做并没有帮助可读性。 - Nanne
使用更好的变量名,您可能不想使用while循环来检查一个数字是否可以被f整除(这是一个单一条件检查,所以听起来像是if吗?)。至于保留因子,您了解Java集合吗? - wkl
2
http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes - Romain Hippeau
我建议您在调试器中逐步执行代码,这将清楚地显示每行代码正在做什么以及为什么要这样做。这将有助于您理解程序,并可能使您明显地了解需要修复的问题。 - Peter Lawrey
14个回答

17
以下代码将返回给定数字的所有因子列表:
public ArrayList<Integer> findFactors(int num) {        
    ArrayList<Integer> factors = new ArrayList<Integer>();

    // Skip two if the number is odd
    int incrementer = num % 2 == 0 ? 1 : 2;

    for (int i = 1; i <= Math.sqrt(num); i += incrementer) {

        // If there is no remainder, then the number is a factor.
        if (num % i == 0) {
            factors.add(i);

            // Skip duplicates
            if (i != num / i) {
                factors.add(num / i);
            }

        }
    }

    // Sort the list of factors
    Collections.sort(factors);

    return factors;
}

这个答案在两个方面上对 Sharad Dargan 的回答 进行了改进:

  1. 基于 这个答案 中使用的一个想法,你可以通过确定数字是偶数还是奇数来决定增量的值,从而加快解决方案的速度。

    在 for 循环之前添加以下代码行:

int incrementer = num % 2 == 0 ? 1 : 2;

然后将循环的最后一部分更改为:

 i += incrementer
如果数字是奇数,则会跳过所有偶数而不管情况如何始终以1递增。

  • Sharad将上限值存储在变量中,然后在for循环中使用该变量:

    int upperlimit = (int)(Math.sqrt(a));
    ...
    for(int i = 1; i <= upperlimit; i+= 1)
    

    直接将Math.sqrt(num)放入for循环中,跳过上限变量:

    for (int i = 1; i <= Math.sqrt(num); i += incrementer) {
    

    这将允许你跳过代码中的强制类型转换部分,创造更加简洁的代码。


  • 接下来是一些可以使用的JUnit测试用例:

    @Test
    public void test12() {
        FindFactors find = new FindFactors();
    
        int num = 12;
        List<Integer> factors = Arrays.asList(1, 2, 3, 4, 6, 12);
    
        assertEquals(factors, find.findFactors(num));
    }
    
    @Test
    public void test1000000() {
        FindFactors find = new FindFactors();
    
        int num = 1000000;
        List<Integer> factors = Arrays.asList(1, 2, 4, 5, 8, 10, 16, 20, 25, 32, 40, 50, 64, 80, 100, 125, 160, 200,
                250, 320, 400, 500, 625, 800, 1000, 1250, 1600, 2000, 2500, 3125, 4000, 5000, 6250, 8000, 10000, 12500,
                15625, 20000, 25000, 31250, 40000, 50000, 62500, 100000, 125000, 200000, 250000, 500000, 1000000);
    
        assertEquals(factors, find.findFactors(num));
    }
    
    @Test
    public void test1() {
        FindFactors find = new FindFactors();
    
        int num = 1;
        List<Integer> factors = Arrays.asList(1);
    
        assertEquals(factors, find.findFactors(num));
    }
    
    @Test
    public void test0() {
        FindFactors find = new FindFactors();
    
        int num = 0;
        List<Integer> factors = new ArrayList<Integer>();
    
        assertEquals(factors, find.findFactors(num));
    }
    

    1
    将 Math.sqrt 直接放在里面会使它变慢,因为 int-double 比较相对于 int-int 比较来说速度较慢。此外,在编译器启动之前,它必须不断评估 Math.sqrt,这非常缓慢。 - Will Kanga

    11
    public class Solution {
        public ArrayList<Integer> allFactors(int a) {
    
            int upperlimit = (int)(Math.sqrt(a));
            ArrayList<Integer> factors = new ArrayList<Integer>();
            for(int i=1;i <= upperlimit; i+= 1){
                if(a%i == 0){
                    factors.add(i);
                    if(i != a/i){
                        factors.add(a/i);
                    }
                }
            }
            Collections.sort(factors);
            return factors;
        }
    }
    

    上述解决方案的工作方式类似于计算质因数。不同之处在于,对于每个质因数,我们都会继续计算产品的其他部分,即所需数字。


    1
    我在这里添加了另一个答案(https://dev59.com/CGoy5IYBdhLWcg3wScPb#45789083),它是这个解决方案的稍微更快更干净的版本。我在答案中包含了差异的详细说明。 - Tot Zam

    11

    以下是获取给定数字的所有因子的方法。

    public class Factors {
    
        public static void main(String[] args){
            int n = 420;
    
            for(int i=2; i<=n; i++){
                while(n%i==0){
                    System.out.println(i + "| " + n);
                    System.out.println(" -----");
                    n = n/i;
                }
            }
        }
    }
    

    输出:

    2| 420
     -----
    2| 210
     -----
    3| 105
     -----
    5| 35
     -----
    7| 7
     -----
    

    我认为这不是所有的因素... 这个调整似乎有效: ```public static int getFactors(int n) { int last = 0; if (n<=1) { return 1; } for(int i=2; i<=n; i++){ if(n%i==0){ System.out.println(i + "| " + n); System.out.println(" -----"); last = i; } } if (last != 0) { return getFactors(n/last); } else { return 1; } }``` - GL2014
    2
    这将给出所有质因数,而不是给定数字的所有因数。 - Liadco

    3
    为了找到一个给定数字的因数,只需要检查该数字的平方根以下的数字。
    例如,要找到6的因数,只需要检查到2.45(√6)即可。6的因数将是1和2,以及它们的相反数,即3和6。
    我已经编写了一个程序来确定给定数字的因数并显示它们。以下是必要的代码:
        Scanner input = new Scanner(System.in);
    
        System.out.print("Enter integer: ");
        long num = input.nextLong();
    
        for(long i = 1; i <= Math.sqrt(num); i++) {
            if(num % i == 0) {
                System.out.println(i);
                if(i != num/i) {
                    System.out.println(num/i);
                }
            }
        }
    

    您只需要这个程序来查找给定数字的因数。然而,如果您想进一步展示这些因数按照升序排列,则必要的代码如下:
        Scanner input = new Scanner(System.in);
    
        System.out.print("Enter integer: ");
        long num = input.nextLong();
    
        ArrayList<Long> list1 = new ArrayList<>(), list2 = new ArrayList<>();
    
        long currentTime = System.currentTimeMillis();
    
        for(long i = 1; i <= Math.sqrt(num); i++) {
            if(num % i == 0) {
                list1.add(i);
                if(i != num/i) {
                    list2.add(num/i);
                }
            }
        }
    
        int n1 = list1.size() - 1;
        int n2 = list2.size() - 1;
    
        for(int i = 0; i <= n1; i++) {
            System.out.println(list1.get(i));
        }
    
        for(int i = n2; i >= 0; i--) {
            System.out.println(list2.get(i));
        }
    

    功能:该程序将数字的因子存储在一个列表(list1)中,最大值为该数字的平方根;同时将这些数字的倒数存储在另一个列表(list2)中。然后打印出两个列表的元素(如所示)。


    作为将因子按升序排列的替代方法,您可以使用Sharad Dargan帖子中所示的_Collections.sort(listName)_。 - Jainil Ajmera

    2
    你的for循环没有问题,但在这里使用while循环是不正确的。你的for循环逻辑如下:
    • ff设置为1。
    • 只要ff <= f,就继续进行。
    • 完成for循环中的所有操作后,将ff加1。
    看起来这正是你想要的。
    然而,while循环并不正确。只要fff的因数,它就会继续执行你编写的代码,因此除非在while代码中更改它们,否则你将得到一个无限循环。但是,将其更改为if语句将给你想要的结果。
    由于你正在检查因数,所以实际上并不需要检查所有可能性直到f-仅需检查到f的平方根。每当发现ff是因数时,请输出fff/ff作为因数,除非f是平方数。

    1
    public static void printFactors(int number) {
        if (number < 1 )
            System.out.println("Invalid Value");
    
        for (int i = 1 ; i <= number ; ++i) {
            if ( number % i == 0)
                    System.out.println(i);
            }
        }
    }
    

    0

    看起来你在 while 循环中没有对 fff 做任何操作?如果是这样,表达式 f%ff != 0 要么是 false(然后它将进入 for 循环的下一个),要么是 true,那么它将陷入无限循环。

    你确定需要像这样使用 while 吗?


    0

    我用这个方法得到了所有的因子(我只是修改了问题中的算法)。

    int num1 = 120;
    
    for(int num2=1;num2<=num1;num2++)
    {
      if (num1%num2 != 0)
        System.out.println(num2);
    }
    

    0

    这就是你如何像老板一样亲自编写它。需要添加if语句来处理1和2,但除此之外;这种方法非常性感。

      public static void primerize(int n){
      boolean reduced = false;
      while(n > 2){
         if(n%2 == 0){
            System.out.println(2 + "," + n/2);
            n /= 2;
         }
         else{
            int i = isPrime(n); 
            if(i == n && reduced == false){
               System.out.println(1 + "," + n);
               n /= n;
            }
            else if(i == n){
               n/= n;
            }
            else{
               System.out.println(i + "," + n/i);
               n = i;
               reduced = true;
            }
         }
      }}
    
    
    
    public static int isPrime(int n){
      for(int i = (n/3); i > 0; i--){
         if(i == 1){
            return n;
         }
         else if(n%i == 0){
            return i;
         }
      }
      return 0;}
    

    0

    利用Java 8中引入的流(Streams),以下代码将打印给定数字的因数。

    int input = 1500;
    IntStream.rangeClosed(1, input)
             .filter(e -> input % e == 0)
             .forEach(System.out::println);
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接