在给定字符串的排列的排序列表中查找给定排列的索引

时间:2011-02-27 04:42:55

标签: algorithm permutation

我们给了一个字符串和一个字符串的排列。

例如,输入字符串sandeep和排列psdenae

在原始字符串排列的排序列表中查找给定排列的位置。

6 个答案:

答案 0 :(得分:30)

长度为n的给定字符串的排列总数为 n!(如果所有字符都不同),因此无法探索所有组合。

这个问题实际上就像数学P& C问题

按字典顺序排列时,查找单词“stack”的排名。

将输入字符串指定为NILSU 拿一个我们必须找到排名的词。以“SUNIL”为例。

  

现在按字母顺序排列“SUNIL”字母。

     

会的。 “我是你的。”

     

现在拿第一个字母。它的“我”。现在检查,是字母“我”了   “SUNIL”的第一个字母?不可以。可以形成的单词数量   从我开始将是4!,所以我们知道会有4个!话   在“SUNIL”之前。

     

我= 4! = 24

     

现在去找第二封信。它的“L”。现在再次检查一下   我们想要的第一个位置的信?不,所以单词的数量可以是   从“L”开始形成的将是4!。

     

L = 4! = 24

     

现在去“N”。这是我们要的吗?不。记下单词数量   可以用“N”开头,再一次4!

     

N = 4! = 24

     

现在去“S”。这是我们想要的吗?是。现在删除来自的信   按字母顺序排列的单词。它现在将是“I L N U”

     

写入S并在列表中再次检查该单词。我们想要SI吗?没有。   因此,从SI开始可以形成的单词数量为3!

     

[S]:I-> 3! = 6

     

Go for L.我们想要SL吗?不,所以它将是3!。

     

[S]:1→ 3! = 6

     

去N.我们想要SN吗?否。

     

[S]:N-> 3! = 6

     

去SU吧。这是我们要的吗?是。从列表中剪下字母U.   然后它将是“我L N”。现在试试I.我们想要SUI吗?不,那么号码   可以形成从SUI开始的单词!

     

[SU]:I-> 2! = 2现在去L.我们想要“SUL”。号码所以数量   以SUL开头的单词将是2!。

     

[SU]:1→ 2! = 2

     

现在去N.我们想要SUN吗?是的,现在删除那封信。还有这个   将是“我L”。我们想要“SUNI”吗?是。删除那封信。唯一的   左边的字母是“L”。

     

现在去找L.我们想要SUNIL吗?是。 SUNIL是第一个选择,所以   我们有1个! [SUN] [I] [L] = 1! = 1

     

现在添加我们得到的整数。总和将是。

     

24 + 24 + 24 + 6 + 6 + 6 + 2 + 2 + 1 = 95。

因此,如果我们计算可以使用字典顺序排列的SUNIL字母创建的单词,那么单词SUNIL将位于第95位。

因此,通过这种方法,您可以非常轻松地解决这个问题。

答案 1 :(得分:1)

建立@Algorithmist的答案,以及他对答案的评论,并使用this post中讨论的原则,当有重复的字母时,我在JavaScript中制作了以下算法,适用于所有人基于字母的单词,即使是重复的字母实例。

function anagramPosition(string) {
  var index = 1;
  var remainingLetters = string.length - 1;
  var frequencies = {};
  var splitString = string.split("");
  var sortedStringLetters = string.split("").sort();

  sortedStringLetters.forEach(function(val, i) {
    if (!frequencies[val]) {
      frequencies[val] = 1;
    } else {
      frequencies[val]++;
    }
  })

  function factorial(coefficient) {
    var temp = coefficient;
    var permutations = coefficient;
    while (temp-- > 2) {
      permutations *= temp;
    }
    return permutations;
  }

  function getSubPermutations(object, currentLetter) {
    object[currentLetter]--;
    var denominator = 1;
    for (var key in object) {
      var subPermutations = factorial(object[key]);
      subPermutations !== 0 ? denominator *= subPermutations : null;
    }
    object[currentLetter]++;
    return denominator;
  }

  var splitStringIndex = 0;
  while (sortedStringLetters.length) {
    for (var i = 0; i < sortedStringLetters.length; i++) {
      if (sortedStringLetters[i] !== splitString[splitStringIndex]) {
        if (sortedStringLetters[i] !== sortedStringLetters[i+1]) {
          var permutations = factorial(remainingLetters);
          index += permutations / getSubPermutations(frequencies, sortedStringLetters[i]);
        } else {
          continue;
        }
      } else {
        splitStringIndex++;
        frequencies[sortedStringLetters[i]]--;
        sortedStringLetters.splice(i, 1);
        remainingLetters--;
        break;
      }
    }
  }
  return index;
}

anagramPosition("ARCTIC") // => 42

我没有评论代码,但我确实尝试将变量名称作为解释。如果您使用开发工具控制台通过调试器进程运行它并输入一些console.logs,您应该能够看到它如何使用上面链接的S.O.中的公式。交。

答案 2 :(得分:0)

我试图在js中实现这个。它适用于没有重复字母的字符串,但我得到错误的计数。这是我的代码:

function x(str) {
var sOrdinata = str.split('').sort()
console.log('sOrdinata = '+ sOrdinata)
var str = str.split('')
console.log('str = '+str)
console.log('\n')
var pos = 1;

for(var j in str){
//console.log(j)

for(var i in sOrdinata){
if(sOrdinata[i]==str[j]){
  console.log('found, position: '+ i)
  sOrdinata.splice(i,1)
  console.log('Nuovo sOrdinata = '+sOrdinata)
  console.log('\n')
  break;
}
else{
  //calculate number of permutations
  console.log('valore di j: '+j)

  //console.log('lunghezza stringa da permutare: '+str.slice(~~j+1).length);
  if(str.slice(j).length >1 ){sub = str.slice(~~j+1)}else {sub = str.slice(j)}
  console.log('substring to be used for permutation: '+ sub)

  prep = nrepC(sub.join(''))
  console.log('prep = '+prep)

  num = factorial(sub.length)
  console.log('num = '+num)

  den = denom(prep)
  console.log('den = '+ den)

  pos += num/den
  console.log(num/den)
  console.log('\n')
 }
 }
}
console.log(pos)
return pos
}



/* ------------ functions used by main --------------- */ 

function nrepC(str){
var obj={}
var repeats=[]
var res= [];

for(x = 0, length = str.length; x < length; x++) {
var l = str.charAt(x)
obj[l] = (isNaN(obj[l]) ? 1 : obj[l] + 1);
}
//console.log(obj)

for (var i in obj){
if(obj[i]>1) res.push(obj[i])
}
if(res.length==0){res.push(1); return res}
else return res
}

function num(vect){
var res =  1

}


function denom(vect){
var res = 1
for(var i in vect){
res*= factorial(vect[i])
}
return res
}


function factorial (n){
if (n==0 || n==1){
return 1;
}
return factorial(n-1)*n;
}  

答案 3 :(得分:0)

有点太晚了,但仅作为参考......你可以直接使用这个C#代码。

它会起作用但是......

唯一重要的是通常,您应该将唯一值作为起始集。否则你就没有了!排列。你还有别的东西(少于n!)。当项目可能是重复的时候,我对任何有用的用法有点怀疑。

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>
        /// <returns>The result is written in property: Result</returns>
        public void GetValuesForIndex(long sortIndex)
        {
            int size = _sortedValues.Length;

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

            if (sortIndex >= MaxIndex)
            {
                throw new ArgumentException("sortIndex should be 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;
        }

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

答案 4 :(得分:-1)

我解决问题的方法是对给定的排列进行排序。 字符串中字符的交换次数将为排列的排序列表中的排列位置提供位置。

答案 5 :(得分:-1)

效率低下的解决方案是连续找到先前的排列,直到找到无法置换的字符串。达到此状态所需的排列数是原始字符串的位置。

但是,如果使用组合学,则可以更快地实现解决方案。如果字符串长度超过12,之前的解决方案将产生非常慢的输出。