【问题标题】:How to generate every integer with a set of digits?如何用一组数字生成每个整数?
【发布时间】:2013-07-23 20:51:45
【问题描述】:

我想生成每个包含0,1,2,2,4,4int(如果集合更大,则生成longs)。 对于少量的数字,用手很容易做到,但我不明白我怎么能做到。

对于一个不太大的整数集,比如我的示例,我们可以使用类似的东西:

for(i = 102244; i <= 442210; i++){
   //check if the digits are in the number
   //add it to a tree
}

但是正如你所看到的,对于更大的集合,复杂性远不是我们能做的最好的(O(10n),但我可能错了)。您对如何执行此操作有任何提示吗?

样本是随机选择的,不是家庭作业!

这是我的解决方案,但它并没有真正针对大量数字进行优化,但可能会对某些人有所帮助:

@Test
public void testPossibleNumbers(){
    TreeSet<Long> possibleNumbers = new TreeSet<Long>();
    String a = "012244";
    permutation("",a,possibleNumbers);
    LOGGER.info("Array of possible numbers"); //breapoint: 150 solutions
}

private static void permutation(String prefix, String str, TreeSet<Long> tree) {
    int n = str.length();
    if (n == 0 && !prefix.startsWith("0")){
        tree.add(Long.parseLong(prefix));
    }
    else {
        for (int i = 0; i < n; i++)
            permutation(prefix + str.charAt(i), str.substring(0, i) + str.substring(i+1, n), tree);
    }
}

【问题讨论】:

  • @Fabinout:只是想清楚一点。另外,你想如何处理前导 0?对于您的示例,012244 是解决方案吗?
  • @CodieCodeMonkey 当然,012244 不是遵守我的法律的整数;)
  • 顺便说一句,for应该从12244开始
  • @StefanoFalasca 不,因为 12244 不包含 0
  • Here's some code to efficiently generate permutations without duplicates. 提示 - 为了避免数字以 0 开头,您需要在 if 语句中添加一个简单的检查,以确保您没有将 0 放在第一个位置。

标签: java algorithm


【解决方案1】:

您只需枚举起始“集合”的所有排列(它实际上不是集合,它包含重复项)。当然,您最终可能会得到一些重复项(因为您不是从一个集合开始的)和以(任意数量的)0(es)开头的数字,您应该考虑到这一点。

我要做的是使用某种不接受重复项的容器(c++ 中的 std::set),然后使用 012244 012244 012424 012442 ... 442210 中的排列开始将数字推入其中

容器会考虑重复,零“问题”不会成为问题,因为 0*10^5+1*10^4+...+2 不会跟踪前导“0”。

【讨论】:

  • 可以通过将其重写为 0, 1, 21, 22, 41, 42 并在打印前将其转换回来轻松地使其成为一个集合。然后是简单的组合。
  • 我使用 Java,但我明白你的意思。除了我不知道如何以相当快的方式排列数字。
  • 不知道java中的任何具体内容,这可以帮助吗? stackoverflow.com/questions/5876716/…
  • @StefanoFalasca 感谢您,我找到了方法。我编辑我的问题以添加答案,并验证您的答案。
  • 很高兴能帮到您。
【解决方案2】:

我将首先将您的数据从具有重复的列表转换为将 10 个可能数字中的每一个映射到可用次数的字典。有些条目的重复次数为 0,表示不使用该数字。

我们将从左到右进行,这样我们就可以处理在最左边的位置不使用 0 的业务。

1) 对于最左边的位置,使用字典构建一个候选数字列表。将 0 排除在此列表之外。 2) 建立下一个地方的候选名单,考虑之前的选择。每个候选列表都放在一个堆栈上。

对于 OP 给出的数据 0、1、2、2、4、4,我们构建以下堆栈:

{4}        num = 102244
{4}        num = 10224_
{2, 4}     num = 1022__
{2, 4}     num = 102___ (0 and 1 are all used)
{0, 2, 4}  num = 10____ (since we've used all the ones)
{1, 2, 4}  num = 1_____ (since 0 is not allowed on the left)

3) 回溯。从堆栈顶部的选择列表中删除第一个数字,它已被使用。将下一个选项放在整数的适当位置。如果没有更多选择,则弹出堆栈,直到可以做出选择为止。

所以在第 3 步之后堆栈看起来像:

{4}        num = 1024__
{2, 4}     num = 102___ (0 and 1 are all used)
{0, 2, 4}  num = 10____ (since we've used all the ones)
{1, 2, 4}  num = 1_____ (since 0 is not allowed on the left)

4) 按照步骤 1 和 2 重建堆栈。

{4}        num = 102424
{2, 4}     num = 10242_
{4}        num = 1024__
{2, 4}     num = 102___ (0 and 1 are all used)
{0, 2, 4}  num = 10____ (since we've used all the ones)
{1, 2, 4}  num = 1_____ (since 0 is not allowed on the left)

5) 继续这种方式,直到无法做出更多选择为止。

请注意,此方法仅发出有效数字,并且不会重复。

工作 python 代码:

data = [0, 1, 2, 2, 4, 4]
results = []

# Number of digits
n = len(data)

# initialize the counts
counts = dict((i, 0) for i in range(10))
for digit in data:
    counts[digit] += 1

# We use this to keep track of the digits that have been used
used = dict((i, 0) for i in range(10))


choice_stack = []

# This is where we'll store the digits
slots = []

first = True
while first or len(choice_stack) > 0:

    # build phase
    while True:
        choices = []
        for i in range(10):
            # no 0 allowed in the left-most place
            if i == 0 and first:
                first = False
                continue
            if counts[i] - used[i] > 0:
                choices.append(i)

        # Leave the build phase if we've used all of our digits
        if len(choices) == 0:
            break;

        choice_stack.append(choices)
        slots.append(choices[0])
        used[choices[0]] += 1

    # Compute the integer
    num = 0
    for i in range(n):
        num += 10**i * slots[-i - 1]
    results.append(num)

    # backtrack phase
    while len(choice_stack) > 0:
        choices = choice_stack.pop()
        slots.pop()
        used[choices[0]] -= 1

        del choices[0]
        if len(choices) == 0:
            continue

        # next choice
        choice_stack.append(choices)
        slots.append(choices[0])
        used[choices[0]] += 1
        break

# Format the results
import sys
for i in range(len(results)):
    if i%6:
        sys.stdout.write(' ')
    else:
        sys.stdout.write('\n')
    sys.stdout.write(str(results[i]))
sys.stdout.write('\n')

输出是:

102244 102424 102442 104224 104242 104422
120244 120424 120442 122044 122404 122440
124024 124042 124204 124240 124402 124420
140224 140242 140422 142024 142042 142204
142240 142402 142420 144022 144202 144220
201244 201424 201442 202144 202414 202441
204124 204142 204214 204241 204412 204421
210244 210424 210442 212044 212404 212440
214024 214042 214204 214240 214402 214420
220144 220414 220441 221044 221404 221440
224014 224041 224104 224140 224401 224410
240124 240142 240214 240241 240412 240421
241024 241042 241204 241240 241402 241420
242014 242041 242104 242140 242401 242410
244012 244021 244102 244120 244201 244210
401224 401242 401422 402124 402142 402214
402241 402412 402421 404122 404212 404221
410224 410242 410422 412024 412042 412204
412240 412402 412420 414022 414202 414220
420124 420142 420214 420241 420412 420421
421024 421042 421204 421240 421402 421420
422014 422041 422104 422140 422401 422410
424012 424021 424102 424120 424201 424210
440122 440212 440221 441022 441202 441220
442012 442021 442102 442120 442201 442210

【讨论】:

  • 好的,感谢您的宝贵时间,这实现起来相当复杂,我会立即尝试。
  • @Fabinout,你用的是什么语言?
  • @Fabinout,我希望 python,我可以用 python 快速编写代码,但我对 Java 很生疏。
  • 我可以很容易地阅读 Python,如果你不介意,我会欢迎一些代码 :)
  • @Fabinout:已添加 Python 源代码。
猜你喜欢
  • 2014-09-04
  • 1970-01-01
  • 2023-04-06
  • 1970-01-01
  • 2013-01-03
  • 1970-01-01
  • 2018-07-16
  • 2017-02-16
  • 1970-01-01
相关资源
最近更新 更多