1.下一个排列
实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须 原地 修改,只允许使用额外常数空间。
考察知识点:两遍扫描
思路:
1.首先从后向前查找第一个顺序对(i,i+1),满足 a[i] < a[i+1]。这样「较小数」即为a[i]。此时 [i+1,n)必是下降序列。
2.如果找到了顺序对,那么在区间 [i+1,n)中从后向前查找第一个元素 j 满足 a[i] < a[j]。这样「较大数」即为 a[j]。
3.交换a[i]与a[j],此时可以证明区间[i+1,n) 必为降序。我们可以直接使用双指针反转区间[i+1,n) 使其变为升序,而无需对该区间进行排序。
class Solution {
public:
void nextPermutation(vector<int>& nums) {
int i = nums.size() - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) i--;
if (i >= 0)
{
int j = nums.size() - 1;
while (j >= 0 && nums[i] >= nums[j]) j--;
swap(nums[i], nums[j]);
}
reverse(nums.begin() + i + 1, nums.end());
}
};
2.全排列
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
考察知识点:回溯
class Solution {
public:
vector<vector<int>> ans;
vector<vector<int>> permute(vector<int>& nums) {
sort(nums.begin(), nums.end());
perm(nums, 0, nums.size() - 1);
return ans;
}
void perm(vector<int> nums, int left, int right) {
if (left == right)
{
ans.push_back(nums);
return;
}
for (int i = left; i <= right; i++)
{
swap(nums[left], nums[i]);
perm(nums, left + 1, right);
}
}
};
3.全排列 II
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
考察知识点:回溯
class Solution {
public:
vector<vector<int>> ans;
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(), nums.end());
perm(nums, 0, nums.size() - 1);
return ans;
}
void perm(vector<int> nums, int left, int right) {
if (left == right)
{
ans.push_back(nums);
return;
}
for (int i = left; i <= right; i++)
{
if (i != left && nums[left] == nums[i]) continue;
swap(nums[left], nums[i]);
perm(nums, left + 1, right);
}
}
};
4.排列序列
给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
"123""132""213""231""312"“321”
给定 n 和 k,返回第 k 个排列。
作死解法:(调库函数)
class Solution {
public:
string getPermutation(int n, int k) {
string s="";
for(int i=1;i<=n;++i)
s+=to_string(i);
do{
--k;
if(k==0) break;
}while(next_permutation(s.begin(),s.end()));
return s;
}
};
憨憨解法:(回溯所有可能)
class Solution {
public:
string getPermutation(int n, int k) {
string s="";
for(int i=1;i<=n;++i)
s+=to_string(i);
perm(s,0,s.size()-1,k);
return ans[k-1];
}
vector<string> ans;
void perm(string str, int left, int right, int num) {
if (left == right)
{
ans.push_back(str);
if(ans.size()==num)
return;
}
else
{
for (int i = left; i <= right; i++)
{
swap(str[left], str[i]);
perm(str, left + 1, right, num);
}
}
}
};
大佬解法:(逆康托展开)
class Solution {
public:
string getPermutation(int n, int k) {
vector<char> chs={'1','2','3','4','5','6','7','8','9'};
vector<int> factor={1,1,2,6,24,120,720,5040,40320,362880};
string str="";
for(--k; n--; k%=factor[n])
{
int i=k/factor[n];
str+=chs[i];
chs.erase(chs.begin()+i);
}
return str;
}
};
本文深入探讨了多种排列相关算法,包括下一个排列、全排列及其变种、排列序列等问题的解决方法。通过具体实例介绍了如何利用回溯法和特殊技巧来求解这些经典问题。
414

被折叠的 条评论
为什么被折叠?



