Permutation Problems
When to use Permutation
- to check all possible placements
- when asked how many possibilities, arrangements, posssible sequences which involve all the characters
Formulae
- The number of permutations of
ndistinct objects is n factorial, usually written asn!.
So the time complexity of any problem related to permulations is n!
Permutation TERMS used in Problem Statements
Permutation of length N
A permutation of length
nis an array of sizenconsisting ofndistinct integers in therange [1, n]. For example,(3, 2, 4, 1)is a permutation of length4,- but `(3, 3, 1, 4)` and `(2, 3, 4, 5)` are **not**, as `(3, 3, 1, 4)` contains **duplicate elements**, and `(2, 3, 4, 5)` contains elements **not in** `range [1,4]`.
good Permutation -- codechef
permutation P good, if the maximum element of the first half of P is less than(<) the minimum element of the second half of P.
next_permutation C++ <algorithm>
sequence MUST be sorted to use next_permutation
<algorithm> header has next_permutation(str.begin(), str.end) which can be used in two ways
converts sequence to next lexicographically larger PERMUTATION
// str = "abcaa"
while (next_permutation(str.begin(), str.end()))
// now the str is Converted into "acaab"
check if the current string or sequence is lexicographically maximum i.e. no more other permutations can be formed.
while (next_permutation(str.begin(), str.end()))
// returns true or false
Create all permutaions of string
same as leetcode Permutation-1
by swapping
for loop (swapping ⏩ callingFunction ⏩ swappingBack)
my intution
- here first I have to take each element by a
forloop, and then I willswapthe currentindex=ifrom for loop with theindex=givenPosI have from the user- in my for loop
istarts withgivenPosbecoz I want my next elements to swap with each other to make add up to my cuurent combination. Also becoz I want my string to iget bigger in length from my currentgivenPos
- in my for loop
- when calling the
recursiveFunctionhere I want my sequence to be of same size So, I will NOTreturnanything is my base case as I am making changes to the string direrctly aarrangement needs to change for permutation, So, I amswappingelements here. - Now after
swapping ⏩ callingFunctionI will have to swap those elements back i.e.backtrackingbecoz I want the original sequenc back as my work with the current sequence is over
by adding elements
class Solution {
void helper(unordered_map<int, int>& bar, vector<int>& temp, vector<vector<int>>& res, int n){
if(temp.size() == n){
res.push_back(temp);
return ;
}
for(auto &i : bar){
if(i.second <= 0) continue;
i.second --;
temp.push_back(i.first);
helper(bar, temp, res, n);
temp.pop_back();
i.second ++;
}
}
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
vector<vector<int>> res;
unordered_map<int, int> bar;
for(int i : nums){
bar[i] ++;
}
vector<int> temp;
helper(bar, temp, res, nums.size());
return res;
}
};
my thought process
My intution here is :
- NO
posis required as the permutation must have size equal to the given sequence. - only if my sequence has reached length of
Nonly then I will add it to result as the permutation will contain all elements of the sequence only in different combinmations/order. - I will use a for loop to take each element form
0 to nand then I will check if that particular element has been taken before or not, if not taken then I will add that element to my permutationSequence and then I will call for therecursiveFunction, So that all other elements can also be added with my current element in all type of arrangements as myrecursiveFunctionwill take each of them and repeat all steps again and again.- After calling for the
recursiveFunctionI MUST REMOVE the added element and also mark that element is_NOT_taken becoz So that the element before it in my newpermutationSequencecan have other combinations. But this element will eventually be taken by recursion in any other for loop as mymaphas marked it as element_NOT_taken.
- After calling for the
using `map` to store elements and then itrerating through the map. If **not using map** then must `sort()` the sequence before doing anything.
Another type of solution using an array storing index of each element: 'but need to sort as map is not used: Striver great Permutation Video
vector<vector<int>> ans;
map<int, int> mp;
void foo(vector<int>& perm, vector<int>& nums) { `pos` is NOT used as recursion is called from inside for loop
if (perm.size() == nums.size()) {
ans.emplace_back(perm);
return;
}
for (auto &el:mp) { // must PASS BY REFERENCE "&" as making `changes directly `to the `el` of map
if (el.second <= 0) continue;
--el.second;
perm.emplace_back(el.first);
foo(perm, nums);
perm.pop_back();
++el.second;
}
}
main(){
for(auto el:nums) {
++mp[el];
}
vector<int> perm;
foo(perm, nums); // no `pos` is required here
}
using next_permutation()
int main()
{
string str;
cin >> str;
vector<string> v;
sort(str.begin(), str.end());
v.emplace_back(str);
int sum = 1;
while (next_permutation(str.begin(), str.end()))
{
++sum;
v.emplace_back(str);
}
// can print now
}
all Permutations WITH duplicates
The given sequence has duplicates
by swapping and checking
by adding elements and checking if already taken
class Solution {
void helper(unordered_map<int, int>& bar, vector<int>& temp, vector<vector<int>>& res, int n){
if(temp.size() == n){
res.push_back(temp);
return ;
}
for(auto &i : bar){
if(i.second <= 0) continue;
i.second --;
temp.push_back(i.first);
helper(bar, temp, res, n);
temp.pop_back();
i.second ++;
}
}
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
vector<vector<int>> res;
unordered_map<int, int> bar;
for(int i : nums){
bar[i] ++;
}
vector<int> temp;
helper(bar, temp, res, nums.size());
return res;
}
};
my thought process
My intution here is :
- NO
posis required as the permutation must have size equal to the given sequence. - only if my sequence has reached length of
Nonly then I will add it to result as the permutation will contain all elements of the sequence only in different combinmations/order. - I will use a for loop to take each element form
0 to nand then I will check if that particular element has been taken before or not, if not taken then I will add that element to my permutationSequence and then I will call for therecursiveFunction, So that all other elements can also be added with my current element in all type of arrangements as myrecursiveFunctionwill take each of them and repeat all steps again and again.- After calling for the
recursiveFunctionI MUST REMOVE the added element and also mark that element is_NOT_taken becoz So that the element before it in my newpermutationSequencecan have other combinations. But this element will eventually be taken by recursion in any other for loop as mymaphas marked it as element_NOT_taken.
- After calling for the
vector<vector<int>> ans;
map<int, int> mp;
void foo(vector<int>& perm, vector<int>& nums) { `pos` is NOT used as recursion is called from inside for loop
if (perm.size() == nums.size()) {
ans.emplace_back(perm);
return;
}
for (auto &el:mp) { // must PASS BY REFERENCE "&" as making `changes directly `to the `el` of map
if (el.second <= 0) continue;
--el.second;
perm.emplace_back(el.first);
foo(perm, nums);
perm.pop_back();
++el.second;
}
}
main(){
for(auto el:nums) {
++mp[el];
}
vector<int> perm;
foo(perm, nums); // no `pos` is required here
}
using next_permutation()
int main()
{
string str;
cin >> str;
vector<string> v;
sort(str.begin(), str.end());
v.emplace_back(str);
int sum = 1;
while (next_permutation(str.begin(), str.end()))
{
++sum;
v.emplace_back(str);
}
// can print now
}
next Permutation
Steps:
- go throught the sequence in reverse order & find and element at index
iwose next element at indexi+1isv[i] > v[i+1and choose that index as pivot index - go throught the sequence in reverse order & find the first element which is greater than the element at pivot index
- now
swapthe greater element's index and pivot index
- now
- sort the elements of indices next to the swapped pivot element index
void nextPermutation(vector<int> &nums)
{
int pivot = -1;
// 1. go throught the sequence in reverse order & find and element at index `i` wose next element at index `i+1` is `v[i] > v[i+1` and choose that index as **pivot index**
for (int i = nums.size() - 2; i >= 0; i--)
{
if (nums.at(i) < nums.at(i + 1))
{
pivot = i;
break;
}
}
if (pivot >= 0)
{
for (int i = nums.size() - 1; i >= 0; i--)
{
cout << "now" << i << endl;
if (nums.at(i) > nums.at(pivot))
{
swap(nums.at(i), nums.at(pivot)); // 2. `swap` the greater element's index and pivot index
sort(nums.begin() + pivot + 1, nums.end()); // 3. sort the elements of indices next to the swapped pivot element index
break;
}
}
}
else
{
sort(nums.begin(), nums.end());
}
}