Given a string str, the task is to generate all the distinct permutations of the given string iteratively.
Examples:
Input: str = “bba”
Output:
abb
bab
bbaInput: str = “abc”
Output:
abc
acb
bac
bca
cab
cba
Approach: The number of permutations for a string of length n are n!. The following algorithm can be extended to arrays of arbitrary objects too. Here only the case of generating permutations of strings are covered.
The algorithm generates them in an iterative fashion and is as follows:
We will go through the steps using the example input string “abca”.
The first step of the algorithm maps each letter to a number and stores the number of occurrences of each letter. For that, the string is first sorted.
Modified input string: “aabc”
Now the letters would be mapped as follows:
(first: mapped Number, second: Count)
a : 0, 2
b : 1, 1
c : 2, 0
The base of the number system we use would be 3 (equal to the number of distinct characters in the input string)
Now an array would hold the mapped values of each letter. The basic idea is to increment the array as a combined number in the number system with base equal to the number of distinct characters.
So initially the array would be [0, 0, 1, 2]
We add 1 to this and the new array is [0, 0, 2, 0] (Number system is 3: we simply added 0012 and 1 in base 3 system)
We check the number of occurrences of each number in the array and check it with the occurrences of each letter in the original reference array. In this case [0, 0, 2, 0] is an invalid sequence as count(0) > number of zeros (or ‘a’, the character mapped to 0) in the original string
We repeat the process until our array equals [2, 1, 0, 0], i.e. the largest valid number that can be generated and therefore exhausting all permutations.
This approach runs with a complexity of O(n(n + 1)).
Optimizing the algorithm
The basic premise still remains the same. Now, however, the algorithm tries to avoid many irrelevant and useless states or permutations.
The function generatePermutation(string) prepares the reference table (ref vector in code) which stores the mapped character for each index and its occurrences. It also prepares the word of mapped integers. (array of integers to permute).
The function calls the function getNext(args…) which alters the array to the next permutation. When there is overflow (all permutations generated) then the function returns END. Else it returns VALID.
To get the next state, therefore, we first increment the array by 1 as done in the previous approach. We keep track of the range of indices that were changed due to the addition.
Example:
Incrementing [0, 2, 2, 2] gives [1, 0, 0, 0] with the range of changed indices {1, 2, 3} or [1, 3]. After that, we start from the leftmost index and check if it is a valid number.
The number is valid if the substring before left i.e. [0, left) has instances of the value a[left] strictly lesser than n, where n is the number of occurrences of a[left] in the original array.
- Check Validity for left.
- If there is no conflict, increment left go to step 1. Break if left == last index of array.
- Else increment a[left], if a[left] < base (number of distinct elements), go to step 1.
- Else add 1 to the subarray [0, left] and get the new left index which starts the range of changed parts. Go to step 1.
The function returns VALID if the permutation generated is valid, END if overflow occurs.
The validity checking is done by helper function hasConflict(args…) which simply checks the subarray [0, left) for occurrences of a[left].
If the number of occurrences is strictly less than the occurrences of a[left] in the original array then it returns true else false.
By checking and adding to indices to the left first, we skip many states that would otherwise have crept up in the algorithm.
The algorithm goes through a maximum of O(n) states for each state.
Therefore, Time complexity: O(n * n!)
Space complexity: O(n)
Below is the implementation of the above approach:
// C++ implementation of the approach #include <bits/stdc++.h> using namespace std;
// No more permutations can be generated #define END -1 // Permutation is valid #define VALID 1 // Utility function to print the // generated permutation void printString(vector< int >& word,
vector<pair< char , int > >& ref)
{ for ( int i = 0; i < word.size(); i++) {
cout << ref[word[i]].first;
}
cout << "\n" ;
} // Function that checks for any conflict present // in the word/string for the index bool hasConflict(vector< int >& word,
vector<pair< char , int > >& ref, int index)
{ // Check number of instances where value of
// the character is equal to the
// value at checking index
int conflictCount = 0;
for ( int i = 0; i < index; i++) {
if (word[i] == word[index])
conflictCount++;
}
// If the number of instances are greater
// than the number of occurrences of the
// character then conflict is present
if (conflictCount < ref[word[index]].second) {
return false ;
}
return true ;
} // Function that returns the validity of the // next permutation generated and makes // changes to the word array int getNext(vector< int >& word,
vector<pair< char , int > >& ref, int mod)
{ int left, right, carry;
right = word.size() - 1;
carry = 1;
// Simply add 1 to the array word following
// the number system with base mod
// generates a new permutation
for (left = right; left >= 0; left--) {
if (left == 0 && word[left] + carry >= mod) {
return END; // overflown
}
if (word[left] + carry >= mod) {
word[left] = (word[left] + carry) % mod;
}
else {
word[left] = word[left] + carry;
break ;
}
}
// All the values between left and right (inclusive)
// were changed and therefore need to be
// adjusted to get a valid permutation
while (left <= right) {
while (hasConflict(word, ref, left) && word[left] < mod) {
// Increment till conflict between substring [0, i)
// is resolved or word[left] goes above mod
word[left]++;
}
if (word[left] >= mod) {
// The value for left has crossed mod therefore
// all the values for word with [0, left)
// constant have been converted therefore add 1
// to the substring [0, left) to get a new value
// of left which represents all affected parts.
// Repeat the process of conflict resolvation
// and validity checking from this new left
word[left] %= mod;
int carry = 1;
left--;
while (left >= 0) {
if (left == 0 && word[left] + carry >= mod) {
// Overflow
return END;
}
if (word[left] + carry >= mod) {
word[left] = (word[left] + carry) % mod;
left--;
}
else {
word[left] = (word[left] + carry);
break ;
}
}
}
else {
// Increment left if conflict is resolved
// for current index and do conflict
// resolution for the next index
left++;
}
}
return VALID;
} // Iterative function to generate all the // distinct permutations of str void generatePermutations(string str)
{ if (str.size() == 0)
return ;
// First sort the string to assign mapped values
// and occurrences to each letter
// Sorting needs to handle letters
// with multiple occurrences
sort(str.begin(), str.end());
// Reference vector to store the mapping of
// its index to its corresponding char
// and the number of occurrences of the character
// as the second element of the pair
vector<pair< char , int > > ref(str.size());
// Assign each character its index and the
// number of occurrences
int count = 0;
ref[count] = make_pair(str[0], 1);
for ( int i = 1; i < str.size(); i++) {
// Increment occurrences if character is repeated
// Else create new mapping for the next character
if (str[i] == str[i - 1]) {
ref[count].second++;
}
else {
count++;
ref[count] = make_pair(str[i], 1);
}
}
// Size may differ in case of multiple
// occurrences of characters
ref.resize(count + 1);
// Construct the word
// Word stores the mapped values for every letter
// in a permuted sequence i.e. say for "abc"
// word would be initially [0, 1, 2] or "aba", [0, 1, 0]
vector< int > word;
for ( int i = 0; i < ref.size(); i++) {
for ( int j = 0; j < ref[i].second; j++)
word.push_back(i);
}
// mod is the number of distinct letters in string
int mod = ref.size();
int flag = VALID;
while (flag != END) {
// If the permutation sent by getNext
// is valid then print it
printString(word, ref);
// Get the next permutation, validity
// stored in flag
flag = getNext(word, ref, mod);
}
} // Driver code int main()
{ string str = "abc" ;
generatePermutations(str);
return 0;
} |
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class GFG {
// C# implementation of the approach
static String ans = "" ;
// No more permutations can be generated
static final int END = - 1 ;
// Permutation is valid
static final int VALID = 1 ;
// Utility function to print the generated permutation
static void printString(List<Integer> word, List<Pair<Character, Integer>> refList) {
StringBuilder str = new StringBuilder();
for ( int index : word) {
str.append(refList.get(index).first);
}
if (str.length() != 0 )
ans = "\n" + str + ans;
}
// Function that checks for any conflict present
// in the word/string for the index
static boolean hasConflict(List<Integer> word, List<Pair<Character, Integer>> refList, int index) {
if (index >= word.size() || word.get(index) >= refList.size())
return false ;
// Check number of instances where value of
// the character is equal to the
// value at checking index
int conflictCount = 0 ;
for ( int i = 0 ; i < index; i++) {
if (word.get(i).equals(word.get(index)))
conflictCount++;
}
// If the number of instances are greater
// than the number of occurrences of the
// character then conflict is present
if (conflictCount < refList.get(word.get(index)).second)
return false ;
return true ;
}
// Function that returns the validity of the
// next permutation generated and makes
// changes to the word array
static int getNext(List<Integer> word, List<Pair<Character, Integer>> refList, int mod) {
int left, right, carry;
right = word.size() - 1 ;
carry = 1 ;
// Simply add 1 to the array word following
// the number system with base mod
// generates a new permutation
for (left = right; left >= 0 ; left--) {
if (left == 0 && word.get(left) + carry >= mod) {
return END; // overflown
}
if (word.get(left) + carry >= mod) {
word.set(left, (word.get(left) + carry) % mod);
} else {
word.set(left, word.get(left) + carry);
break ;
}
}
// All the values between left and right (inclusive)
// were changed and therefore need to be
// adjusted to get a valid permutation
while (left <= right) {
while (hasConflict(word, refList, left) && word.get(left) < mod) {
// Increment till conflict between substring [0, i)
// is resolved or word.get(left) goes above mod
word.set(left, word.get(left) + 1 );
}
if (word.get(left) >= mod) {
// The value for left has crossed mod therefore
// all the values for word with [0, left)
// constant have been converted therefore add 1
// to the substring [0, left) to get a new value
// of left which represents all affected parts.
// Repeat the process of conflict resolution
// and validity checking from this new left
word.set(left, word.get(left) % mod);
carry = 1 ;
left--;
while (left >= 0 ) {
if (left == 0 && word.get(left) + carry >= mod) {
// Overflow
return END;
}
if (word.get(left) + carry >= mod) {
word.set(left, (word.get(left) + carry) % mod);
left--;
} else {
word.set(left, word.get(left) + carry);
break ;
}
}
} else {
// Increment left if conflict is resolved
// for the current index and do conflict
// resolution for the next index
left++;
}
}
return VALID;
}
// Iterative function to generate all the
// distinct permutations of str
static void generatePermutations(String str) {
if (str.length() == 0 )
return ;
// First sort the string to assign mapped values
// and occurrences to each letter
// Sorting needs to handle letters
// with multiple occurrences
char [] charArray = str.toCharArray();
List<Character> charList = new ArrayList<>();
for ( char c : charArray) {
charList.add(c);
}
Collections.sort(charList, Collections.reverseOrder());
StringBuilder sortedStr = new StringBuilder();
for ( char c : charList) {
sortedStr.append(c);
}
// Reference list to store the mapping of
// its index to its corresponding char
// and the number of occurrences of the character
// as the second element of the pair
List<Pair<Character, Integer>> refList = new ArrayList<>();
// Assign each character its index and the
// number of occurrences
int count = 0 ;
refList.add( new Pair<>(sortedStr.charAt( 0 ), 1 ));
for ( int i = 1 ; i < sortedStr.length(); i++) {
// Increment occurrences if the character is repeated
// Else create a new mapping for the next character
if (sortedStr.charAt(i) == sortedStr.charAt(i - 1 )) {
refList.set(count, new Pair<>(refList.get(count).first, refList.get(count).second + 1 ));
} else {
count++;
refList.add( new Pair<>(sortedStr.charAt(i), 1 ));
}
}
// Size may differ in case of multiple
// occurrences of characters
while (refList.size() > count + 1 ) {
refList.remove(refList.size() - 1 );
}
while (refList.size() < count + 1 ) {
refList.add( new Pair<>( '\0' , 0 ));
}
// Construct the word
// Word stores the mapped values for every letter
// in a permuted sequence i.e. say for "abc"
// word would be initially [0, 1, 2] or "aba", [0, 1, 0]
List<Integer> word = new ArrayList<>();
for ( int i = 0 ; i < refList.size(); i++) {
for ( int j = 0 ; j < refList.get(i).second; j++)
word.add(i);
}
// mod is the number of distinct letters in the string
int mod = refList.size();
int flag = VALID;
while (flag != END) {
// If the permutation sent by GetNext
// is valid then print it
printString(word, refList);
// Get the next permutation, validity
// stored in flag
flag = getNext(word, refList, mod);
}
System.out.println(ans);
}
// Driver code
public static void main(String[] args) {
String str = "abc" ;
generatePermutations(str);
}
// Pair class to store two elements together
static class Pair<A, B> {
A first;
B second;
public Pair(A first, B second) {
this .first = first;
this .second = second;
}
}
} // This code is contributed by phasing17 |
# No more permutations can be generated END = - 1
# Permutation is valid VALID = 1
ans = ""
# Utility function to print the generated permutation def printString(word, ref):
global ans
str = ""
for i in word:
str + = ref[i][ 0 ]
if len ( str ) ! = 0 :
ans = "\n" + str + ans
# Function that checks for any conflict present in the word/string for the index def hasConflict(word, ref, index):
if index > = len (word) or word[index] > = len (ref):
return False
conflictCount = 0
for i in range (index):
if word[i] = = word[index]:
conflictCount + = 1
if conflictCount < ref[word[index]][ 1 ]:
return False
return True
# Function that returns the validity of the next permutation generated # and makes changes to the word list def getNext(word, ref, mod):
left = right = len (word) - 1
carry = 1
while left > = 0 :
if left = = 0 and word[left] + carry > = mod:
return END # overflown
if word[left] + carry > = mod:
word[left] = (word[left] + carry) % mod
else :
word[left] = word[left] + carry
break
left - = 1
while left < = right:
while hasConflict(word, ref, left) and word[left] < mod:
word[left] + = 1
if word[left] > = mod:
word[left] % = mod
carry = 1
left - = 1
while left > = 0 :
if left = = 0 and word[left] + carry > = mod:
return END # Overflow
if word[left] + carry > = mod:
word[left] = (word[left] + carry) % mod
left - = 1
else :
word[left] = (word[left] + carry)
break
else :
left + = 1
return VALID
# Iterative function to generate all the distinct permutations of a string def generatePermutations(s):
global ans
if len (s) = = 0 :
return
s = list (s)
s.sort(reverse = True )
s = "".join(s)
# Reference list to store the mapping of its index to its corresponding char
# and the number of occurrences of the character as the second element of the pair
ref = []
count = 0
ref.append([s[ 0 ], 1 ])
for i in range ( 1 , len (s)):
if s[i] = = s[i - 1 ]:
ref[count][ 1 ] + = 1
else :
count + = 1
ref.append([s[i], 1 ])
mod = len (ref)
flag = VALID
word = [i for i in range ( len (ref)) for j in range (ref[i][ 1 ])]
while flag ! = END:
printString(word, ref)
flag = getNext(word, ref, mod)
print (ans)
# Driver code str_val = "abc"
generatePermutations(str_val) |
using System;
using System.Collections.Generic;
class GFG
{ // C# implementation of the approach
static string ans = "" ;
// No more permutations can be generated
static int END = -1;
// Permutation is valid
static int VALID = 1;
// Utility function to print the generated permutation
static void PrintString(List< int > word, List<Tuple< char , int >> refList)
{
string str = "" ;
foreach ( var index in word)
{
str += refList[index].Item1;
}
if (str.Length != 0)
ans = "\n" + str + ans;
}
// Function that checks for any conflict present
// in the word/string for the index
static bool HasConflict(List< int > word, List<Tuple< char , int >> refList, int index)
{
if (index >= word.Count || word[index] >= refList.Count)
return false ;
// Check number of instances where value of
// the character is equal to the
// value at checking index
int conflictCount = 0;
for ( int i = 0; i < index; i++)
{
if (word[i] == word[index])
conflictCount++;
}
// If the number of instances are greater
// than the number of occurrences of the
// character then conflict is present
if (conflictCount < refList[word[index]].Item2)
return false ;
return true ;
}
// Function that returns the validity of the
// next permutation generated and makes
// changes to the word array
static int GetNext(List< int > word, List<Tuple< char , int >> refList, int mod)
{
int left, right, carry;
right = word.Count - 1;
carry = 1;
// Simply add 1 to the array word following
// the number system with base mod
// generates a new permutation
for (left = right; left >= 0; left--)
{
if (left == 0 && word[left] + carry >= mod)
{
return END; // overflown
}
if (word[left] + carry >= mod)
{
word[left] = (word[left] + carry) % mod;
}
else
{
word[left] = word[left] + carry;
break ;
}
}
// All the values between left and right (inclusive)
// were changed and therefore need to be
// adjusted to get a valid permutation
while (left <= right)
{
while (HasConflict(word, refList, left) && word[left] < mod)
{
// Increment till conflict between substring [0, i)
// is resolved or word[left] goes above mod
word[left]++;
}
if (word[left] >= mod)
{
// The value for left has crossed mod therefore
// all the values for word with [0, left)
// constant have been converted therefore add 1
// to the substring [0, left) to get a new value
// of left which represents all affected parts.
// Repeat the process of conflict resolvation
// and validity checking from this new left
word[left] %= mod;
carry = 1;
left--;
while (left >= 0)
{
if (left == 0 && word[left] + carry >= mod)
{
// Overflow
return END;
}
if (word[left] + carry >= mod)
{
word[left] = (word[left] + carry) % mod;
left--;
}
else
{
word[left] = (word[left] + carry);
break ;
}
}
}
else
{
// Increment left if conflict is resolved
// for current index and do conflict
// resolution for the next index
left++;
}
}
return VALID;
}
// Iterative function to generate all the
// distinct permutations of str
static void GeneratePermutations( string str)
{
if (str.Length == 0)
return ;
// First sort the string to assign mapped values
// and occurrences to each letter
// Sorting needs to handle letters
// with multiple occurrences
char [] charArray = str.ToCharArray();
Array.Sort(charArray, (a, b) => b.CompareTo(a));
str = new string (charArray);
// Reference list to store the mapping of
// its index to its corresponding char
// and the number of occurrences of the character
// as the second element of the pair
List<Tuple< char , int >> refList = new List<Tuple< char , int >>();
// Assign each character its index and the
// number of occurrences
int count = 0;
refList.Add(Tuple.Create(str[0], 1));
for ( int i = 1; i < str.Length; i++)
{
// Increment occurrences if character is repeated
// Else create a new mapping for the next character
if (str[i] == str[i - 1])
{
refList[count] = Tuple.Create(refList[count].Item1, refList[count].Item2 + 1);
}
else
{
count++;
refList.Add(Tuple.Create(str[i], 1));
}
}
// Size may differ in case of multiple
// occurrences of characters
while (refList.Count > count + 1) { refList.RemoveAt(refList.Count - 1); }
while (refList.Count < count + 1) { refList.Add(Tuple.Create( '\0' , 0)); }
// Construct the word
// Word stores the mapped values for every letter
// in a permuted sequence i.e. say for "abc"
// word would be initially [0, 1, 2] or "aba", [0, 1, 0]
List< int > word = new List< int >();
for ( int i = 0; i < refList.Count; i++)
{
for ( int j = 0; j < refList[i].Item2; j++)
word.Add(i);
}
// mod is the number of distinct letters in string
int mod = refList.Count;
int flag = VALID;
while (flag != END)
{
// If the permutation sent by GetNext
// is valid then print it
PrintString(word, refList);
// Get the next permutation, validity
// stored in flag
flag = GetNext(word, refList, mod);
}
Console.WriteLine(ans);
}
// Driver code
static void Main()
{
string str = "abc" ;
GeneratePermutations(str);
}
} // This code is contributed by phasing17 |
// JS implementation of the approach let ans = ""
// No more permutations can be generated let END = -1 // Permutation is valid let VALID = 1 // Utility function to print the // generated permutation function printString(word, ref)
{ let str = ""
for ( var i = 0; i < word.length; i++)
str += ref[word[i]][0];
if (str.length != 0)
ans = "\n" + str + ans
} // Function that checks for any conflict present // in the word/string for the index function hasConflict(word, ref, index)
{ if (index >= word.length || word[index] >= ref.length)
return false ;
// Check number of instances where value of
// the character is equal to the
// value at checking index
let conflictCount = 0;
for ( var i = 0; i < index; i++) {
if (word[i] == word[index])
conflictCount++;
}
//console.log(ref, word, index, word[index]);
// If the number of instances are greater
// than the number of occurrences of the
// character then conflict is present
if (conflictCount < ref[word[index]][1]) {
return false ;
}
return true ;
} // Function that returns the validity of the // next permutation generated and makes // changes to the word array function getNext(word, ref, mod)
{ let left, right, carry;
right = word.length - 1;
carry = 1;
// Simply add 1 to the array word following
// the number system with base mod
// generates a new permutation
for (left = right; left >= 0; left--) {
if (left == 0 && word[left] + carry >= mod) {
return END; // overflown
}
if (word[left] + carry >= mod) {
word[left] = (word[left] + carry) % mod;
}
else {
word[left] = word[left] + carry;
break ;
}
}
// All the values between left and right (inclusive)
// were changed and therefore need to be
// adjusted to get a valid permutation
while (left <= right) {
while (hasConflict(word, ref, left) && word[left] < mod) {
// Increment till conflict between substring [0, i)
// is resolved or word[left] goes above mod
word[left]++;
}
if (word[left] >= mod) {
// The value for left has crossed mod therefore
// all the values for word with [0, left)
// constant have been converted therefore add 1
// to the substring [0, left) to get a new value
// of left which represents all affected parts.
// Repeat the process of conflict resolvation
// and validity checking from this new left
word[left] %= mod;
let carry = 1;
left--;
while (left >= 0) {
if (left == 0 && word[left] + carry >= mod) {
// Overflow
return END;
}
if (word[left] + carry >= mod) {
word[left] = (word[left] + carry) % mod;
left--;
}
else {
word[left] = (word[left] + carry);
break ;
}
}
}
else {
// Increment left if conflict is resolved
// for current index and do conflict
// resolution for the next index
left++;
}
}
return "VALID" ;
} // Iterative function to generate all the // distinct permutations of str function generatePermutations(str)
{ if (str.length == 0)
return ;
// First sort the string to assign mapped values
// and occurrences to each letter
// Sorting needs to handle letters
// with multiple occurrences
str = str.split( "" )
str.sort( function (a, b) {
if (a > b) {
return -1;
}
if (b > a) {
return 1;
}
return 0;
}); str = str.join( "" )
// Reference vector to store the mapping of
// its index to its corresponding char
// and the number of occurrences of the character
// as the second element of the pair
let ref = new Array(str.length);
// Assign each character its index and the
// number of occurrences
let count = 0;
ref[count] = [str[0], 1];
for (let i = 1; i < str.length; i++) {
// Increment occurrences if character is repeated
// Else create new mapping for the next character
if (str[i] == str[i - 1]) {
ref[count][1] ++;
}
else {
count++;
ref[count] = [str[i], 1];
}
}
// Size may differ in case of multiple
// occurrences of characters
while (ref.length > count + 1) { ref.pop(); }
while (ref.length < count + 1) { ref.push([0, 0]); }
// Construct the word
// Word stores the mapped values for every letter
// in a permuted sequence i.e. say for "abc"
// word would be initially [0, 1, 2] or "aba", [0, 1, 0]
let word = [];
for ( var i = 0; i < ref.length; i++) {
for ( var j = 0; j < ref[i][1]; j++)
word.push(i);
}
// mod is the number of distinct letters in string
var mod = ref.length;
var flag = VALID;
while (flag != END) {
// If the permutation sent by getNext
// is valid then print it
printString(word, ref);
// Get the next permutation, validity
// stored in flag
flag = getNext(word, ref, mod);
}
console.log(ans)
} // Driver code let str = "abc" ;
generatePermutations(str); // This code is contributed by phasing17 |
abc acb bac bca cab cba