java—如何在数组中保存素数分解的值?

laik7k3q  于 2021-07-06  发布在  Java
关注(0)|答案(2)|浏览(313)

我现在的问题是,我需要对给定的数做一个素因子分解。然后我需要将值(除数和幂)存储到一个2d数组中。 x[0][] = the dividers and x[1][] the powers. 所以f.ex。如果数字是8,那么除法器是2,幂是3,因为2^3=8
这是我的密码:
我的第一步是在数字1的情况下检查数组是否为空

public static long[][] primfactorization(long givenNumber) {

    if (givenNumber == 1) {
        long [][] empty = {{},{}};
        return empty;
    }

然后第二步是声明一些变量并创建稍后必须返回的2d数组(我也使用sqrt而不是math.sqrt,因为这里禁止使用javaapi的类/方法)。这里的问题是,我知道第一个括号必须有大小2,因为它只有2行(除法器和幂),但我还不知道我应该在第二个括号中输入什么,因为我不知道每个数字将有多少除法器。

int index = 0;
int count = 0;
int i=2;
long z = (long) sqrt(n);
long[][] a = new long[2][ (int) z];

然后我从“实”素因子分解开始,它工作得非常好。这里的主要问题是我无法将除法器和幂保存到数组中。就像我尝试使用一个名为index的新变量(在我的方法开始时声明)那样,但是它可以将同一个除法器保存多次f.ex。 x[0][1] = 2 and x[0][2] = 2 我只需要一次。此外,电源还没有按预期的那样工作,因为它从1开始,每次循环完成时只上升1,但它应该上升相同的分频器出现的数量(f.ex。分频器2出现3次,则功率应为3)。提前感谢。

while(givenNumber%2==0) {
givenNumber=givenNumber/2;
count++; //power   8 = 2.2.2 => count = 3
}
i++;
for (i = 3; i <= z; i = i+2) {
// While i divides l, print i and divide l
while (givenNumber%i == 0) {
    int temp = i;
 //ToDo: save the divider in array[0][]
    count++; //ToDo: save the power in array[1][]
    givenNumber = givenNumber/i;
    i = temp;
    a[0][index] = temp;
    a[1][index] = count;
    index++;
  }
}
return a;
}
deyfvvtc

deyfvvtc1#

我建议使用 Map 为了这个。键可以是实际因子和值,也可以是计数。这消除了包含数组超过其长度或必须过度分配空间以容纳潜在因子的可能性。

int[] test = { 25, 282, 301, 292922, Integer.MAX_VALUE };
for (int n : test) {
    Map<Integer, Integer> factors = findFactors(n);
    System.out.println(n + " -> " + factors);
}

印刷品

25 -> {5=2}
282 -> {2=1, 3=1, 47=1}
301 -> {7=1, 43=1}
292922 -> {2=1, 7=4, 61=1}
2147483647 -> {2147483647=1}

如果需要,可以在从方法返回因子之前或打印因子之前将Map转换为数组。这是后者的一个例子。

for (int n : test) {
    Map<Integer, Integer> factors = findFactors(n);
    int[][] results = factors.entrySet().stream()
            .map(e -> new int[] { e.getKey(), e.getValue() })
            .toArray(int[][]::new);
    System.out.println(n + " -> " + Arrays.deepToString(results));  
}

印刷品

25 -> [[5, 2]]
282 -> [[2, 1], [3, 1], [47, 1]]
301 -> [[7, 1], [43, 1]]
292922 -> [[2, 1], [7, 4], [61, 1]]
2147483647 -> [[2147483647, 1]]

下面是返回一个Map的方法。请注意 BigInteger 用于检查当前更新的值是否为素数。这对于实现最佳性能至关重要。例如,当一个非常大的数是相对较小的素数和一个非常大的素数的乘积时。要看区别,试试看 Integer.MAX_VALUE 有没有那张支票。

public static Map<Integer, Integer> findFactors(int val) {
    Map<Integer, Integer> factors = new HashMap<>();

    // the initial prime
    int prime = 2;
    int c = 1;

    while (val > 1) {

        // update divisions and add to the map.
        int count = 0;
        while (val % prime == 0) {
            count++;
            val /= prime;
        }
        if (count > 0) {
            factors.put(prime, count);
        }

        // now do a check to see if the current value is a prime.
        if (BigInteger.valueOf(val).isProbablePrime(99)) {
            factors.put(val, 1);
            break;
        }
        // compute next factor.
        prime = (c++ * 2 + 1);

    }
    return factors;
}

注: Integer.MAX_VALUE 是一个形式为2n-1的mercenne素数,其中 n 是质数。在这种情况下, n = 31 .

jtoj6r0c

jtoj6r0c2#

for (i = 2; i <= z; i = i+2) {
    count = 0;
    while (n%i == 0) {
        count++;
        n = n/i;
    }
    if (count > 0) {
        x[0][index] = i;
        x[1][index] = count;
        index++;
    }
    if (i == 2)
        --i;
}
return x;

我对“实际因子分解”部分做了一些修改: count 必须为除数i的每个新值设置为零
我已经移动了数组的赋值 x 在while循环之外。理想情况下,只有在计算了“功率”之后才能进行。只有在 count > 0 .
远离的 temp . 这是不必要的。
我注意到对于除数,你只检查奇数,并在开始时额外检查2。但是,数组 x 2没有相应更新。我已经删除了while循环,2的因子检查现在与for循环中的其他数字一起完成。我为2的特例添加了一个if语句,以获得与预期相同的结果。
我还不知道我应该在第二个括号里输入什么,因为我不知道每个数字将有多少除法器。
事先计算尺寸要求是不切实际的。因为javaapi不能使用,所以创建一个函数来有效地改变数组的大小是最简单的。这实现了列表的可调整大小,同时只使用数组。

/**
@return the reference to be assigned to x
@param - arr: The array x
@param - newSize: The array size can be increased or decreased to newSize

* /

static long[][] resize(long[][] arr, int newSize) {
    long[][] temp = new long[2][newSize];
    for(int i = 0; i < arr[0].length && i < newSize; ++i) {
        temp[0][i] = arr[0][i];
        temp[1][i] = arr[1][i];
    }
    return temp;
}

使用此功能:
当数组 x 是满的,它的大小可以任意增加。
当执行完成时 x 可以修剪到正确的大小。
这是正确的工作程序,它显示了一切在行动。试着运行它。

import java.util.Arrays; // I am aware that imports are not allowed, but have used this class only for display of output
import java.util.Scanner;
class Factorizer {
    public static long[][] primfactorization(long n) {
        int index = 0;
        int count = 0;
        long z = (long) Math.sqrt(n);
        long[][] x = new long[2][5];
        for (int i = 2; i <= z; i = i+2) {
            count = 0;
            while (n%i == 0) {
                count++;
                n = n/i;
            }
            if (count > 0) {
                x[0][index] = i;
                x[1][index] = count;
                index++;
            }
            if (index >= x[0].length) // resizing array when it is too small
                x = resize(x, index + 5); // 5 being an arbitrary number
            if (i == 2)
                --i;
        }
        return resize(x, index); //trimming down the size before returning
    }
    static long[][] resize(long[][] arr, int newSize) {
        long[][] temp = new long[2][newSize];
        for(int i = 0; i < arr[0].length && i < newSize; ++i) {
            temp[0][i] = arr[0][i];
            temp[1][i] = arr[1][i];
        }
        return temp;
    }
    public static void main (String[] args)
    {
        System.out.print("Enter a number: ");
        long n = new Scanner(System.in).nextLong();
        System.out.println (Arrays.deepToString(primfactorization(n)));
    }
}

最后说明:
如果1是参数,则不需要进行特殊检查。我把它拿走了。
有一种特殊情况,这个程序不能完全正确地工作。如果一个素数是作为参数给出的,它就不会作为一个因子包含进来。这是因为 for-loop 只运行到 sqrt(n) . 这可以通过将for循环的上限设置为 n ,或通过另一个 if 循环体中的条件。

相关问题