试题链接:字符串的排列_牛客题霸_牛客网
- 思路:暴力回溯每一种取值,去重可以使用哈希也可以通过排序,然后每次再为当前 idx 选取字符的时候保证重复的只选一次即可,可以只选从左到右第一个未被填过的数字。
- 时间复杂度:O(n × n!)
- 空间复杂度:O(n)
class Solution {
public:
vector<string> Permutation(string str) {
vector<string> ans;
int n = str.size();
vector<bool> vis(n);
string path;
path.reserve(n);
sort(str.begin(), str.end());
function<void(int)> backtrack = [&](int idx) {
if (idx == n) {
ans.push_back(path);
}
for (int i = 0; i < n; i++) {
if (vis[i] || (i > 0 && str[i - 1] == str[i] && vis[i - 1])) continue;
vis[i] = true;
path.push_back(str[i]);
backtrack(idx + 1);
path.pop_back();
vis[i] = false;
}
};
backtrack(0);
return ans;
}
};
- 思路:
next_permutation
算法可以求出一个排列下个字典序更大的排列,因此只要我们对字符串排序后不断求出它的下一个排列,即可得到所有排列。注意到下一个排列总是比当前排列要大,除非该排列已经是最大的排列。我们希望找到一种方法,能够找到一个大于当前序列的新序列,且变大的幅度尽可能小。具体地,该算法主要分为如下几步:- 每次从后往前找到第一个满足
str[i] < str[i + 1]
的数, 再从[i + 1, n)
中找到最接近str[i]
并大于str[i]
的第一个数str[j]
,要得到下一个排列,我们应该交换str[i]
和str[j]
,然后让str[i]
后的数从小到大排列 - 实际上,我们不必每次都对
[i + 1, n)
的数都进行排序,可以发现,由于str[j]
是第一个大于str[i]
的数, 故str[j + 1]
一定是小于或等于str[i]
的, 交换str[i]
和str[j]
后,[i + 1, n)
一定是从大到小的序列, 我们只需要对其进行翻转即可
- 每次从后往前找到第一个满足
- 时间复杂度:O(n!)
- 空间复杂度:O(1)
class Solution {
public:
vector<string> Permutation(string str) {
vector<string> ans;
sort(str.begin(), str.end());
do {
ans.push_back(str);
} while (nextPermutation(str));
return ans;
}
bool nextPermutation(string& str) {
int n = str.size();
int i = n - 2;
while (i >= 0 && str[i] >= str[i + 1]) i--;
if (i < 0) return false;
int j = n - 1;
while (str[i] >= str[j]) j--;
swap(str[i], str[j]);
reverse(str.begin() + i + 1, str.end());
return true;
}
};
试题链接:https://leetcode.cn/problems/n-queens-ii/description/
- 思路:用一个记录 0 ~ n - 1 元素的数组表示每一行皇后所在的列,这样可以保证行和列都不在同一行列,对这个数组求所有排列情况,然后对每种排列情况进行判断即可,只需要判断对角线是否存在多余数量的皇后。取任意两个皇后,判断它们的行距和列距是否相同。
- 时间复杂度:O(n!)
- 空间复杂度:O(n)
class Solution {
public:
int totalNQueens(int n) {
int ans = 0;
vector<int> colIndex(n);
iota(colIndex.begin(), colIndex.end(), 0);
do {
bool flag = true;
for (int i = 0; i < n && flag; i++) {
for (int j = i + 1; j < n; j++) {
if (abs(i - j) == abs(colIndex[i] - colIndex[j]))
{
flag = false;
break;
}
}
}
if (flag) ans++;
} while (next_permutation(colIndex.begin(), colIndex.end()));
return ans;
}
};