题目描述:
假设有从 1 到 N 的 N 个整数,如果从这 N 个数字中成功构造出一个数组,使得数组的第 i 位 (1 <= i <= N) 满足如下两个条件中的一个,我们就称这个数组为一个优美的排列。条件:
第 i 位的数字能被 i 整除
i 能被第 i 位上的数字整除
现在给定一个整数 N,请问可以构造多少个优美的排列?
1、不定义新的节点结构体
只用一个stack<int> path维护路径信息,只能用dfs完成,借助pos位完成path出栈条件判断;
class Solution {
public:
int countArrangement(int N) {
stack<pair<int, int>> q;
q.push({-1, 0});
int sum = 0;
deque<int> dq;
while (q.empty() == false) {
pair<int, int> curr = q.top();
q.pop();
dq.push_back(curr.second);
int pos = curr.first;
if (pos == N - 1) {
bool bret = true;
for (int i = 1; i <= N; i++) {
if (dq[N - i + 1] % i != 0 && i % dq[N - i + 1] != 0) {
bret = false;
break;
}
}
if (bret == true) {
sum++;
}
while (q.empty() == false && dq.size() != (q.top().first + 1)) {
dq.pop_back();
}
continue;
}
for (int i = 1; i <= N; i++) {
if (find(dq.begin(), dq.end(), i) != dq.end()) {
continue;
}
q.push({pos + 1, i});
}
}
return sum;
}
};
2、定义新的节点结构体
方式一:每个节点使用vector<int> path维护root到该节点路径信息;
方式二:每个节点使用visited<int>(N + 1, 0)标记已访问节点信息;
重点:
a. 如果定义新的结构体,那么dfs和bfs都可以完成搜索
b. 使用assign函数效率提升约2倍;
c. 拷贝结构体指针效率更高;
while (1) {
if (condition) {
...
}
}
等效为
while (condition) {
...
}
// 拷贝指针还是更优的选择
class Solution {
public:
struct Node {
int pos;
vector<int> visited;
Node (int x) : pos(x) {
};
};
public:
int countArrangement(int N) {
stack<Node*> q;
Node* node = new Node(-1);
node->visited.assign(N + 1, 0);
q.push(node);
int sum = 0;
while (q.empty() == false) {
Node* curr = q.top();
q.pop();
int pos = curr->pos;
if (pos == N - 1) {
sum++;
}
for (int i = 1; i <= N; i++) {
if (curr->visited[i] == 1) {
continue;
}
if (i % (pos + 2) == 0 || (pos + 2) % i == 0) {
Node* tmp = new Node(pos + 1);
// tmp->visited = curr->visited;
tmp->visited.assign(curr->visited.begin(), curr->visited.end());
tmp->visited[i] = 1;
q.push(tmp);
}
}
}
return sum;
}
};