反向排列指数

时间:2017-05-15 11:19:12

标签: javascript algorithm combinatorics discrete-mathematics

我编写了一个函数,用于计算索引中数组[a,b,c,...]的排列,例如:

0 -> a b c 
1 -> a c b 
2 -> b a c
3 -> b c a
4 -> c a b
5 -> c b a     

通过这个递归函数:

function factorial(n) { return n <= 1 ? 1 : n*factorial(n-1); }
function permutation(ar, n) {
   if (ar.length == 1) return [ar[0]]; 
   var x = factorial(ar.length-1);  // get first element
   return ar.splice(Math.floor(n/x),1).concat( permutation( ar, n % x ) )
}

现在我正在寻找一个取排列索引的函数来得到反转排列的索引,即

    index    perm    reversed  reversed index
    **0** -> a b c -> c b a -> **5**
    **1** -> a c b -> b c a -> **3**
    **2** -> b a c -> c a b -> **4**
    **3** -> b c a -> a c b -> **1**
    **4** -> c a b -> b a c -> **2**
    **5** -> c b a -> a b c -> **0**

我可以计算所有排列,计算它们的反向并建立它的索引,但似乎应该有一种数学方法来获得反向排列的索引而不计算它。

3 个答案:

答案 0 :(得分:2)

如果你看看你的排列,你会发现它的结构如下:(例如lenght = 3)

首先,你的排列分为3组,每组包含2个!分子 然后将这些子组分为2组,每组1个!之后,子分组不再分开。

事实上,你的排列可以被查找起来&#39;首先说明它在哪个子组,然后说明它在哪个子组...

例如,排列2:&#39; bac&#39;在子组1(从0开始)和子组0中。

所以我们可以说2 =(1,0),如3 = 1 *(2!)+ 0 *(1!) 那么4将是(2,0) 现在,如果我们翻转2,那么它(0,1)并添加4,(2,0)就可以得到(2,1) 这适用于所有排列

本质上: (n =排列长度)

将您的索引写为*(n-1)! + b *(n-2)! + ... + z *(1!)(a = floor(index /(n-1)),b = floor((index%(n-1))/(n-2)!),... )

找到一个数字,这样如果你翻转最小的一个并将它们加在一起就得到(n-1,n-2,n-3,...,1)

这可能是一种有效的算法。

答案 1 :(得分:0)

我不知道是否有数学方法来实现这一目标,但你可以通过使用hashmap以更快的方式实现这一目标。

var dict = {};

dict['abc'] = 0;
dict['acb'] = 1;
dict['bac'] = 2;  
dict['bca'] = 3;
dict['cab'] = 4;
dict['cba'] = 5; 

所以一旦你有了这个,你可以使用上面形成的hashmap反转普通字符串并获得它的索引值。

希望这有帮助!

答案 2 :(得分:0)

我有点太晚了......可以计算一下。您可以按原样使用此C#代码:

using System;
using System.Collections.Generic;

namespace WpfPermutations
{
    public class PermutationOuelletLexico3<T>
    {
        // ************************************************************************
        private T[] _sortedValues;

        private bool[] _valueUsed;

        public readonly long MaxIndex; // long to support 20! or less 

        // ************************************************************************
        public PermutationOuelletLexico3(T[] sortedValues)
        {
            if (sortedValues.Length <= 0)
            {
                throw new ArgumentException("sortedValues.Lenght should be greater than 0");
            }

            _sortedValues = sortedValues;
            Result = new T[_sortedValues.Length];
            _valueUsed = new bool[_sortedValues.Length];

            MaxIndex = Factorial.GetFactorial(_sortedValues.Length);
        }

        // ************************************************************************
        public T[] Result { get; private set; }

        // ************************************************************************
        /// <summary>
        /// Return the permutation relative to the index received, according to 
        /// _sortedValues.
        /// Sort Index is 0 based and should be less than MaxIndex. Otherwise you get an exception.
        /// </summary>
        /// <param name="sortIndex"></param>
        /// <param name="result">Value is not used as inpu, only as output. Re-use buffer in order to save memory</param>
        /// <returns></returns>
        public void GetValuesForIndex(long sortIndex)
        {
            int size = _sortedValues.Length;

            if (sortIndex < 0)
            {
                throw new ArgumentException("sortIndex should greater or equal to 0.");
            }

            if (sortIndex >= MaxIndex)
            {
                throw new ArgumentException("sortIndex should less than factorial(the lenght of items)");
            }

            for (int n = 0; n < _valueUsed.Length; n++)
            {
                _valueUsed[n] = false;
            }

            long factorielLower = MaxIndex;

            for (int index = 0; index < size; index++)
            {
                long factorielBigger = factorielLower;
                factorielLower = Factorial.GetFactorial(size - index - 1);  //  factorielBigger / inverseIndex;

                int resultItemIndex = (int)(sortIndex % factorielBigger / factorielLower);

                int correctedResultItemIndex = 0;
                for(;;)
                {
                    if (! _valueUsed[correctedResultItemIndex])
                    {
                        resultItemIndex--;
                        if (resultItemIndex < 0)
                        {
                            break;
                        }
                    }
                    correctedResultItemIndex++;
                }

                Result[index] = _sortedValues[correctedResultItemIndex];
                _valueUsed[correctedResultItemIndex] = true;
            }
        }

        // ************************************************************************
        /// <summary>
        /// Calc the index, relative to _sortedValues, of the permutation received
        /// as argument. Returned index is 0 based.
        /// </summary>
        /// <param name="values"></param>
        /// <returns></returns>
        public long GetIndexOfValues(T[] values)
        {
            int size = _sortedValues.Length;
            long valuesIndex = 0;

            List<T> valuesLeft = new List<T>(_sortedValues);

            for (int index = 0; index < size; index++)
            {
                long indexFactorial = Factorial.GetFactorial(size - 1 - index);

                T value = values[index];
                int indexCorrected = valuesLeft.IndexOf(value);
                valuesIndex = valuesIndex + (indexCorrected * indexFactorial);
                valuesLeft.Remove(value);
            }
            return valuesIndex;
        }

        // ************************************************************************
    }
}