【问题标题】:Counting power sets with very large arrays, Java?‽用非常大的数组计算幂集,Java?‽
【发布时间】:2020-04-19 19:58:48
【问题描述】:

我正在做以下编程练习:Counting power sets。声明是:

在这个 kata 中,您必须创建一个函数 powers/Powers,它需要一个 数组,并返回可能从中创建的子集的数量 列表。换句话说,就是计算幂集。

例如

powers([1,2,3]) => 8

...由于...

powers([1,2,3]) => [[], 1, [2], [3], [1,2], [2,3], [1,3], [1,2,3]]

您的函数应该能够计算大小为 500 的集合,所以 小心;那里出现了相当大的数字!

为了比较,我的 Haskell 解决方案可以计算 在不到一秒的时间内完成一个长度为 90 000 的数组,所以要快!

您应该将传递的每个数组视为一组唯一值 卡塔。

示例:

Powers.powers(new int[]{}); // 1 Powers.powers(new int[]{1});
// 2 Powers.powers(new int[]{1,2}); // 4 Powers.powers(new int[]{1,2,3,4}); // 16

我已经写了以下答案:

import java.math.BigInteger;
import java.util.*;
public class Powers {
  public static BigInteger powers/*????*/(int[] list) {
    System.out.println("list: "+Arrays.toString(list));
    System.out.println("list length: "+list.length);
    double pow = Math.pow(2, list.length);
    System.out.println("pow: "+pow);
    return new BigInteger(String.valueOf((long)pow));
  }
}

但是对于 100 数组,它不会输出预期的结果。例如,对于以下数组:

list: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
list length: 100

它输出:

9223372036854775807

代替:

1267650600228229401496703205376

我认为困难是通过将 pow 结果从 double 舍入到 long 产生的,因为它输出:

pow: 1.2676506002282294E30

然后我尝试使用 modPow 来获得更大数字的结果:

import java.math.*;
import java.util.*;
public class Powers {
  public static BigInteger powers/*????*/(int[] list) {
    System.out.println("list: "+Arrays.toString(list));
    System.out.println("list length: "+list.length);
    BigInteger pow = BigInteger.valueOf(2).modPow(BigInteger.valueOf(list.length), BigInteger.valueOf(Long.MAX_VALUE));
    System.out.println("pow: "+pow);
    return new BigInteger(String.valueOf(pow));
  }
}

但是,当我们使用 100 长度的数组进行测试时,输出是:

137438953472

什么时候应该:

1267650600228229401496703205376

我认为挑战是由于 Long.MAX_VALUE 等于 modPow 计算的最大值,因为它输出:

pow: 137438953472

之后我尝试在 modPow 函数中为模数写一个更高的数字,然后我写了这个:

import java.math.*;
import java.util.*;
public class Powers {
  public static BigInteger powers/*????*/(int[] list) {
    System.out.println("list: "+Arrays.toString(list));
    System.out.println("list length: "+list.length);
    BigInteger modulus = BigDecimal.valueOf(Double.POSITIVE_INFINITY).toBigInteger();
    BigInteger pow = BigInteger.valueOf(2).modPow(BigInteger.valueOf(list.length), modulus);
    System.out.println("pow: "+pow);
    return new BigInteger(String.valueOf(pow));
  }
}

但是会抛出以下异常:

java.lang.NumberFormatException: Character I is neither a decimal digit number, decimal point, nor "e" notation exponential mark.
    at java.base/java.math.BigDecimal.<init>(BigDecimal.java:518)
    at java.base/java.math.BigDecimal.<init>(BigDecimal.java:401)
    at java.base/java.math.BigDecimal.<init>(BigDecimal.java:834)
    at java.base/java.math.BigDecimal.valueOf(BigDecimal.java:1304)
    at Powers.powers(Powers.java:7)

我认为它的生成是因为 Double.POSITIVE_INFINITY 给了我们一个比 BigInteger 表示的最高值更大的数字。

因此,前两个代码可以通过以下测试:

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import org.junit.Test;
import org.junit.Ignore;
import java.math.BigInteger;

public class PowersTest {
    
  @Test
  public void testPactical() {
    assertEquals("An empty array should return 1!", Powers.powers(new int[]{}), BigInteger.valueOf(1));
    assertEquals(Powers.powers(new int[]{1}), BigInteger.valueOf(2));
    assertEquals(Powers.powers(new int[]{1,2,3,4,5}), BigInteger.valueOf(32));
  }
  
}

但是这两种代码都很难通过 100 长度的数组测试。

另外我读过:

你能帮我找出如何在 Java 中计算具有非常大数组的幂集吗?‽

编辑:

通过写法解决:

import java.math.*;
import java.util.*;
public class Powers {
  public static BigInteger powers/*????*/(int[] list) {
    return BigInteger.valueOf(2).pow(list.length);
  }
}

【问题讨论】:

  • System.out.println(BigInteger.valueOf(2).pow(list.length));
  • 是的@emil 你是对的,如果我们使用 BigInteger.pow() 它会输出预期的输出,感谢您的帮助。
  • 其实拨打BigInteger.ONE.shiftLeft(list.length)会更高效。 --- 在我的机器上,使用list.length = 90000,它在大约 0.04 秒内构建了一个 27093 位的字符串。

标签: java arrays math numbers biginteger


【解决方案1】:

嗯...我检查了一下,我认为这可行:

public static BigInteger powers(int[] list) {
    return BigInteger.valueOf(2).pow(list.length);
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多