生成长度为n的所有二进制字

时间:2016-02-23 15:21:56

标签: algorithm scala complexity-theory

对于我目前正在实现的算法,我需要处理上一步,我不完全确定它在计算上易于处理。此步骤需要为任意n生成长度为n的所有二进制单词(它可能很大,但实际上不应大于50)。如果我记得很清楚,这具有指数复杂性(O(2^n)),这是不好的。

一个天真的递归实现可能如下:

def gen(n: Int, acc: List[String]) : List[String] = {
  if (n == 0) {
    acc
  } else {
    if (acc.length == 0) {
      gen(n - 1, List("0", "1"))
    } else {
      gen(n - 1, (for (i <- acc) yield i ++ "0") ++ (for (j <- acc) yield j ++ "1"))
    }
  }
}
gen(4, List())  //List(0000, 1000, 0100, 1100, 0010, 1010, 0110, 1110, 0001, 1001, 0101, 1101, 0011, 1011, 0111, 1111)

这适用于小型n,并在n增加时快速冻结我的计算机。

这个问题也可以看作是获得所有自然数[0,2^n - 1]的二进制表示,它可以很容易地并行化,但是这对于n的大值无论如何都不起作用,因为元素是巨大的。

即使这是可能的,另一个问题是大多数数据结构都有一个限制大小(大多数数据Int.MaxValue),但这是另一个故事:)

这个问题确实有解决方案吗?

3 个答案:

答案 0 :(得分:1)

由于private int updateContact(int Id, String contactresult, String alternatecontactresult, Integer prevContactSeq) { StringBuffer contactQuery =new StringBuffer(); contactQuery.append("Update contacttable "); contactQuery.append(" Set phone1=?,"); contactQuery.append(" phone2 =?"); contactQuery.append(" Where contactSeq=?"); contactQuery.append(" And id=?"); System.out.println("Contact Update Query "+contactQuery.toString()); try{ JdbcTemplate jdbcTemplate = this.getJdbcTemplate(); return jdbcTemplate.update(contactQuery.toString(), new Object[] {Long.parseLong(contactresult),Long.parseLong(alternatecontactresult),prevContactSeq,Id}); }catch(DataAccessException dae){ dae.printStackTrace(); //error in making the database update. return 0 to identify that the database update failed return 0; } } 显然支持Long.parseLong - 我对Scala中的编码没有丝毫的线索 - 你可以简单地用它来表示这些词。其余的很简单:
所有长度为scala的二进制字都在BigInteger中。只需从0开始作为起始值和增量:

n

[0 , 1 << n)

这将产生按字典顺序排列的所有单词 更重要的问题是:如果for (bint <- 0L until 1L << n) process(bint) ,你已经结束了2 ^ 40个单词。即使你每个字只使用40位= 5个字节,你最终也会得到5TB的数据。我怀疑你是否有能力处理这么多数据。应该有一个比生成该列表更好的方法。

答案 1 :(得分:1)

您可以使用Stream

  

类Stream实现了惰性列表,其中元素仅在需要时进行评估。

为您的场景创建一个非常简单的流:

def numbers(n: BigInt): Stream[BigInt] = n #:: numbers(n + 1)

然后,您可以使用take来获取/生成n第一个数字:

val stream = numbers(0).take(n)

然后将其转换为二进制String表示形式:

 val stream = numbers(0).take(10).map(_.toString(2))

这也会返回一个Stream。之后,您可以使用stream执行任何操作,每个实例:

 stream.foreach(println)

不确定性能影响,但它是您可以尝试的另一种选择。

答案 2 :(得分:0)

您可以使用范围来执行此操作。如果Integers不足以表示,则使用NumericRange over Long或BigInt:

val numbers = NumericRange[BigInt](0,1000,1)

您可以在需要时使用.toString(2)将数字转换为二进制字符串。您可以将范围转换为列表或任何您想要的。

然而,知道你需要什么是很好的。我想不出一个很好的理由来迭代那么多数字甚至存储它们。如果这是解决另一个问题的一部分,可能有更好的方法来解决它。