给定长度为m的字符串,仅包含小写字母。我们需要按字典顺序找到字符串的第n个排列。
例子:
Input: str[] = "abc", n = 3
Output: Result = "bac"
All possible permutation in
sorted order: abc, acb, bac,
bca, cab, cba
Input: str[] = "aba", n = 2
Output: Result = "aba"
All possible permutation
in sorted order: aab, aba, baa
天真的方法:使用STL按字典顺序查找第n个置换。
高效方法:解决此问题的数学概念。
- The total number of permutation of a string formed by N characters(all distinct) is N!
- The Total number of permutation of a string formed by N characters (where the frequency of character C1 is M1, C2 is M2… and so the frequency of character Ck is Mk) is N!/(M1! * M2! *….Mk!).
- The total number of permutation of a string formed by N characters(all distinct) after fixing the first character is (N-1)!
可以按照以下步骤操作以找到解决方案。
- 计算数组中所有字符的频率。
- 现在,从字符串出现的第一个最小字符(最小索引i,使freq [i]> 0),在将第i个特殊字符为第一个字符之后,计算最大排列数。
- 如果此总和值大于给定的n,则将该字符设置为第一个结果输出字符,并递减freq [i]。其余n-1个字符继续相同。
- 另一方面,如果计数小于所需的n,则对频率表中的下一个字符进行迭代,并一次又一次地更新计数,直到找到一个产生的计数大于所需n的字符为止。
C++
// C++ program to print
// n-th permutation
#include
using namespace std;
#define ll long long int
const int MAX_CHAR = 26;
const int MAX_FACT = 20;
ll fact[MAX_FACT];
// Utility for calculating factorials
void precomputeFactorials()
{
fact[0] = 1;
for (int i = 1; i < MAX_FACT; i++)
fact[i] = fact[i - 1] * i;
}
// Function for nth permutation
void nPermute(char str[], int n)
{
precomputeFactorials();
// Length of given string
int len = strlen(str);
// Count frequencies of all
// characters
int freq[MAX_CHAR] = { 0 };
for (int i = 0; i < len; i++)
freq[str[i] - 'a']++;
// Out string for output string
char out[MAX_CHAR];
// Iterate till sum equals n
int sum = 0;
int k = 0;
// We update both n and sum in this
// loop.
while (sum != n) {
sum = 0;
// Check for characters present in freq[]
for (int i = 0; i < MAX_CHAR; i++) {
if (freq[i] == 0)
continue;
// Remove character
freq[i]--;
// Calculate sum after fixing
// a particuar char
int xsum = fact[len - 1 - k];
for (int j = 0; j < MAX_CHAR; j++)
xsum /= fact[freq[j]];
sum += xsum;
// if sum > n fix that char as
// present char and update sum
// and required nth after fixing
// char at that position
if (sum >= n) {
out[k++] = i + 'a';
n -= (sum - xsum);
break;
}
// if sum < n, add character back
if (sum < n)
freq[i]++;
}
}
// if sum == n means this
// char will provide its
// greatest permutation
// as nth permutation
for (int i = MAX_CHAR - 1;
k < len && i >= 0; i--)
if (freq[i]) {
out[k++] = i + 'a';
freq[i++]--;
}
// append string termination
// character and print result
out[k] = '\0';
cout << out;
}
// Driver program
int main()
{
int n = 2;
char str[] = "geeksquiz";
nPermute(str, n);
return 0;
}
Java
// Java program to print
// n-th permutation
public class PermuteString {
final static int MAX_CHAR = 26;
final static int MAX_FACT = 20;
static long fact[] = new long[MAX_FACT];
// Utility for calculating factorial
static void precomputeFactorirals()
{
fact[0] = 1;
for (int i = 1; i < MAX_FACT; i++)
fact[i] = fact[i - 1] * i;
}
// Function for nth permutation
static void nPermute(String str, int n)
{
precomputeFactorirals();
// length of given string
int len = str.length();
// Count frequencies of all
// characters
int freq[] = new int[MAX_CHAR];
for (int i = 0; i < len; i++)
freq[str.charAt(i) - 'a']++;
// out string for output string
String out = "";
// Iterate till sum equals n
int sum = 10;
int k = 0;
// We update both n and sum
// in this loop.
while (sum >= n) {
// Check for characters
// present in freq[]
for (int i = 0; i < MAX_CHAR; i++) {
if (freq[i] == 0)
continue;
// Remove character
freq[i]--;
// calculate sum after fixing
// a particular char
sum = 0;
int xsum = (int)fact[len - 1 - k];
for (int j = 0; j < MAX_CHAR; j++)
xsum /= fact[freq[j]];
sum += xsum;
// if sum > n fix that char as
// present char and update sum
// and required nth after fixing
// char at that position
if (sum >= n) {
out += (char)(i + 'a');
k++;
n -= (sum - xsum);
break;
}
// if sum < n, add character back
if (sum < n)
freq[i]++;
}
}
// if sum == n means this
// char will provide its
// greatest permutation
// as nth permutation
for (int i = MAX_CHAR - 1;
k < len && i >= 0; i--)
if (freq[i] != 0) {
out += (char)(i + 'a');
freq[i++]--;
}
// append string termination
// character and print result
System.out.println(out);
}
// Driver program to test above method
public static void main(String[] args)
{
// TODO Auto-generated method stub
int n = 2;
String str = "geeksquiz";
nPermute(str, n);
}
}
// This code is contributed by Sumit Ghosh
Python3
# Python3 program to print n-th permutation
MAX_CHAR = 26
MAX_FACT = 20
fact = [None] * (MAX_FACT)
# Utility for calculating factorials
def precomputeFactorials():
fact[0] = 1
for i in range(1, MAX_FACT):
fact[i] = fact[i - 1] * i
# Function for nth permutation
def nPermute(string, n):
precomputeFactorials()
# length of given string
length = len(string)
# Count frequencies of all
# characters
freq = [0] * (MAX_CHAR)
for i in range(0, length):
freq[ord(string[i]) - ord('a')] += 1
# out string for output string
out = [None] * (MAX_CHAR)
# iterate till sum equals n
Sum, k = 0, 0
# We update both n and sum in
# this loop.
while Sum != n:
Sum = 0
# check for characters present in freq[]
for i in range(0, MAX_CHAR):
if freq[i] == 0:
continue
# Remove character
freq[i] -= 1
# calculate sum after fixing
# a particuar char
xsum = fact[length - 1 - k]
for j in range(0, MAX_CHAR):
xsum = xsum // fact[freq[j]]
Sum += xsum
# if sum > n fix that char as
# present char and update sum
# and required nth after fixing
# char at that position
if Sum >= n:
out[k] = chr(i + ord('a'))
n -= Sum - xsum
k += 1
break
# if sum < n, add character back
if Sum < n:
freq[i] += 1
# if sum == n means this char will provide
# its greatest permutation as nth permutation
i = MAX_CHAR-1
while k < length and i >= 0:
if freq[i]:
out[k] = chr(i + ord('a'))
freq[i] -= 1
i += 1
k += 1
i -= 1
# print result
print(''.join(out[:k]))
# Driver Code
if __name__ == "__main__":
n = 2
string = "geeksquiz"
nPermute(string, n)
# This code is contributed by Rituraj Jain
C#
// C# program to print n-th permutation
using System;
public class GFG {
static int MAX_CHAR = 26;
static int MAX_FACT = 20;
static long[] fact = new long[MAX_FACT];
// utility for calculating factorial
static void precomputeFactorirals()
{
fact[0] = 1;
for (int i = 1; i < MAX_FACT; i++)
fact[i] = fact[i - 1] * i;
}
// function for nth permutation
static void nPermute(String str, int n)
{
precomputeFactorirals();
// length of given string
int len = str.Length;
// Count frequencies of all
// characters
int[] freq = new int[MAX_CHAR];
for (int i = 0; i < len; i++)
freq[str[i] - 'a']++;
// out string for output string
string ou = "";
// iterate till sum equals n
int sum = 10;
int k = 0;
// We update both n and sum in this
// loop.
while (sum >= n) {
// check for characters present in freq[]
for (int i = 0; i < MAX_CHAR; i++) {
if (freq[i] == 0)
continue;
// Remove character
freq[i]--;
// calculate sum after fixing
// a particular char
sum = 0;
int xsum = (int)fact[len - 1 - k];
for (int j = 0; j < MAX_CHAR; j++)
xsum /= (int)(fact[freq[j]]);
sum += xsum;
// if sum > n fix that char as
// present char and update sum
// and required nth after fixing
// char at that position
if (sum >= n) {
ou += (char)(i + 'a');
k++;
n -= (sum - xsum);
break;
}
// if sum < n, add character back
if (sum < n)
freq[i]++;
}
}
// if sum == n means this char will provide its
// greatest permutation as nth permutation
for (int i = MAX_CHAR - 1; k < len && i >= 0; i--)
if (freq[i] != 0) {
ou += (char)(i + 'a');
freq[i++]--;
}
// append string termination
// character and print result
Console.Write(ou);
}
// Driver program to test above method
public static void Main()
{
// TODO Auto-generated method stub
int n = 2;
String str = "geeksquiz";
nPermute(str, n);
}
}
// This code is contributed by nitin mittal.
输出:
eegikqszu
复杂度分析:
- 时间复杂度: O(n),其中n是第n个排列。
- 空间复杂度: O(n),其中n是存储频率所需的空间。