如何在允许重复时获得第n个排列?

时间:2015-04-18 13:55:29

标签: java algorithm math permutation

Project Euler 24:数字0,1,2,3,4,5,6,7,8和9的百万分之一的词典排列是什么?

如果允许重复怎么办?比如11111111111223344457等。我怎样才能获得百万分位排列,其中重复也包含在计数中。

请注意输入仍然是相同的。输入中没有重复。

我想生成所有可能的长度为10的密码。密码可以包含重复的字符,所以我希望我的功能也适用于此。

这是给出字符串第n个排列的代码。它的工作原理是,对于n个元素,有n个!排列。并且首先在词典排列中(n-1)!排列将从第一个数字开始,依此类推。

我如何修改它以获得重复的字符串呢?我应该使用的任何特定算法?

为了澄清事情,我不仅需要百万分之一的排列。我需要所有可能的排列。通过在此函数上运行for循环,我可以在不重复的情况下获得所有排列。但我无法通过重复获得排列。我想重复排列。因为我想获得所有可能的密码。如果只允许使用数字,请考虑所有可能包含10个字母的密码。 10 ^ 10。我想要所有这些。

import java.util.*;

public class NthPermutation{

    private static int Factorial(int n){  
        if (n < 0)
            return 0;
         int ans = 1;
         for (int i=1;i<=n;++i)
            ans *= i;
         return ans;
     }

     public static String getNth(List<Integer> original, int permNum){

         List<Integer> numbers = new ArrayList<Integer>(original);  
         String nth = "";
         permNum--;
         int N = numbers.size();  

         for (int i=1;i<N;++i){
             int j = permNum / Factorial(N - i); 
             permNum = permNum % Factorial(N - i);
             nth = nth + numbers.get(j);
             numbers.remove(j);

         if (permNum==0)
             break;
         }

         for (int i=0; i<numbers.size();i++)
             nth = nth + numbers.get(i);

         return nth;
      }

      public static void main(String[] args){

          List<Integer> numbers = new ArrayList<Integer>();     
          for (int i = 0; i < 10; i++) 
              numbers.add(i);

          System.out.println(getNth(numbers,1000000)); 
       }
}

3 个答案:

答案 0 :(得分:2)

如果允许重复,则:

  • 第一个排列是0000000000
  • 第二个排列是0000000001
  • 第十个排列是0000000009
  • 百分位排列为0000000099
  • 千分之一的排列是0000000999
  • 百万个排列是0000999999

等等。

所有这些只是在左侧填充了足够数量的零的数字n-1,以使整个字符串的长度为10。

因此,要获得实际的第n个组合,您需要做的就是(在Python下面的代码段中,您可以轻松地转换为Java):

>>> def find_nth_combination(n):
...     print "0" * (10-len(str(n-1))) + str(n-1)
... 
>>> find_nth_combination(1)
0000000000
>>> find_nth_combination(100)
0000000099
>>> find_nth_combination(9062300000)
9062299999
>>> find_nth_combination(12300000)
0012299999

如果你想通过重复来解决这个问题,你可以have a look here(代码在Python中)。


要获得所有排列,只需浏览所有数字。

所以,你需要做类似的事情:

for x in xrange(1, 1001):
    find_nth_combination(x)

将输出:

0000000000
0000000001
...
...
0000000997
0000000998
0000000999

答案 1 :(得分:2)

我们需要首先了解阶乘数系统(或Factoradic数字系统)来解决这个问题。阶乘数系统使用阶乘值而不是数字的幂(二进制系统使用2的幂,十进制使用10的幂)来表示地点值(或基数)。

地点值(基数)是 -

5!= 120 4!= 24 3!= 6 2!= 2 1!= 1 0!= 1等。 第0位的数字始终为0.第一位的数字(基数= 1!)可以是0或1.第二位的数字(基数为2!)可以是0,1或2上。一般来说,第n位的数字可以取0到n之间的任何值。

前几个数字表示为factoradics -

0 -> 0 = 0*0!
1 -> 10 = 1*1! + 0*0!
2 -> 100 = 1*2! + 0*1! + 0*0!
3 -> 110 = 1*2! + 1*1! + 0*0!
4 -> 200 = 2*2! + 0*1! + 0*0!
5 -> 210 = 2*2! + 1*1! + 0*0!
6 -> 1000 = 1*3! + 0*2! + 0*1! + 0*0!
7 -> 1010 = 1*3! + 0*2! + 1*1! + 0*0!
8 -> 1100 = 1*3! + 1*2! + 0*1! + 0*0!
9 -> 1110
10-> 1200

字符串的第n个词典排列与其事实代表之间存在直接关系。

例如,以下是字符串“abcd”的排列。

0  abcd       6  bacd        12  cabd       18  dabc
1  abdc       7  badc        13  cadb       19  dacb
2  acbd       8  bcad        14  cbad       20  dbac
3  acdb       9  bcda        15  cbda       21  dbca
4  adbc       10  bdac       16  cdab       22  dcab
5  adcb       11  bdca       17  cdba       23  dcba

如果仔细观察,我们可以看到这里的模式。第6个(3!)排列后第一个字母发生变化。第二个字母在2(2!)排列后改变。第三个字母在每次(1!)排列后改变,第四个字母在每次(0!)排列后改变。我们可以使用这种关系直接找到第n个排列。

一旦我们在实际上表示n,我们会考虑其中的每个数字,并将给定字符串中的字符添加到输出中。如果我们需要找到'abcd'的第14个排列。 14 in factoradics - &gt; 2100。

从第一个数字开始 - &gt; 2,String是'abcd'。假设索引从0开始,从字符串中取出位置2处的元素并将其添加到输出。

Output                    String
  c                         abd
  2                         012

下一个数字 - &gt; 1.String现在是'abd'。再次,在位置1处拔出字符并将其添加到输出。

Output                    String
 cb                         ad
 21                         01

下一个数字 - &gt;字符串是'ad'。将位置1的字符添加到输出。

Output                   String
 cba                        d
 210                        0

下一个数字 - &gt;字符串是'd'。将位置0处的字符添加到输出。

Output                   String
 cbad                      ''
 2100

要将给定数字转换为阶乘数字系统,请将数字依次除以1,2,3,4,5,依此类推,直到商数为零。每个步骤的提醒形成了事实代表。

例如,要将349转换为factoradic,

              Quotient        Reminder        Factorial Representation

349/1            349               0                             0
349/2            174               1                            10
174/3            58                0                           010
58/4             14                2                          2010
14/5             2                 4                         42010
2/6              0                 2                        242010

349的Factoradic表示是242010。

答案 2 :(得分:0)

没有重复:

由于您只需要1000000000次排列,因此可以强制解决此问题。从字符串开始:“0123456789”并使用C ++等效的next_permuation,您可以在此处获取函数:http://codeforces.ru/blog/entry/3980。只需迭代一百万次就可以达到解决方案。

有更好的贪婪解决方案,运行速度非常快,你可以在这里阅读:https://math.stackexchange.com/questions/60742/finding-the-n-th-lexicographic-permutation-of-a-string

WITH REPETITIONS:

这个问题在重复时非常简单,因为它相当于只是在开始时用数字和填充0来填充它。

1st permuation: 000000001
15th permuation 000000015
etc.