【问题标题】:Find the index of a given permutation in the sorted list of the permutations of a given string在给定字符串的排列排序列表中查找给定排列的索引
【发布时间】:2011-07-05 03:04:03
【问题描述】:

我们得到一个字符串和字符串的排列。

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

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

【问题讨论】:

  • 好问题!你尝试了什么?
  • 这是一个以第 9 标准完成的课堂问题,不是一个好问题
  • 非常相似的问题在其答案中有一个实现:stackoverflow.com/questions/12146910/…

标签: algorithm permutation


【解决方案1】:

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

这道题其实很像数学P&C题

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

输入字符串为 NILSU 取一个词,我们必须找到排名。以“SUNIL”为例。

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

会的。 "I L N S U"。

现在取第一个字母。它的“我”。现在检查一下,是不是字母“I” “SUIL”的第一个字母? No. 可组成的字数 从 I will be 4! 开始,所以我们知道会有 4!字 在“苏尼尔”之前。

我 = 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

选择 L。我们想要 SL 吗?不。所以它将是 3!。

[S]:L-> 3! = 6

选择 N。我们想要 SN 吗?没有。

[S]:N-> 3! = 6

去苏。这是我们想要的吗?是的。从列表中删除字母 U 并 那么它将是“I L N”。现在试试 I. 我们想要 SUI 吗?不,所以号码 从 SUI 开始的单词可以组成 2!

[SU]:I-> 2! = 2 现在选择 L。我们想要“SUL”吗?没有,所以数量 以 SUL 开头的单词将是 2!。

[SU]:L-> 2! = 2

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

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

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

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

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

所以通过这个方法你可以很容易地解决这个问题。

【讨论】:

  • 对于包含重复单词的字符串,例如BOMBAY 假设我们要找到 BOAYBM 的位置。我们只需要知道BOMBAY总共有6个! /2!组合。
【解决方案2】:

基于@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. 中的公式。发帖。

【讨论】:

    【解决方案3】:

    我尝试在 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;
    }  
    

    【讨论】:

      【解决方案4】:

      有点晚了,但作为参考...您可以直接使用此 C# 代码。

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

      唯一重要的是,通常情况下,您应该将唯一值作为您的起始集。否则你没有 n!排列。你还有别的东西(小于 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;
              }
      
              // ************************************************************************
          }
      }
      

      【讨论】:

        【解决方案5】:

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

        【讨论】:

        • 如果您只想应用气泡交换,那么您就已经出局了。一串长度有10!排列(假设所有字符不同)。对长度为 10 的字符串进行排序最多需要 90 次交换。
        【解决方案6】:

        一个低效的解决方案是依次找到以前的排列,直到找到一个无法再排列的字符串。达到这个状态所需要的排列次数就是原始字符串的位置。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-12-10
          • 1970-01-01
          • 2022-09-23
          • 2019-04-29
          • 2017-05-26
          • 1970-01-01
          • 2015-07-25
          • 1970-01-01
          相关资源
          最近更新 更多