Suppose you have N integers from 1 to N. We define a beautiful arrangement as an array that is constructed by these N numbers successfully if one of the following is true for the ith position (1 ≤ i ≤ N) in this array:
- The number at the ith position is divisible by i.
- i is divisible by the number at the ith position.
Now given N, how many beautiful arrangements can you construct?
题解
对1到N的数组排列,使每一位满足A[i] % i == 0或i % A[i]==0。
DFS回溯,使用used数组记录数字是否已使用
public class Solution {
private int count = 0;
public int countArrangement(int N) {
if(N == 0) return 0;
helper(N, 1, new boolean[N + 1]);
return count;
}
private void helper(int N, int pos, boolean[] used) {
if(pos > N){
count++;
return;
}
for(int i = 1; i <= N; i++){
if(!used[i] && (i % pos == 0 || pos % i == 0)){
used[i] = true;
helper(N, pos + 1, used);
used[i] = false;
}
}
}
}
优化,从后向前而不是从前向后,因为前面的索引值比较小,容易被整除,所以会一直向下搜索。从后往前则可以在比较浅的位置中断错误路径
...
public int countArrangement(int N) {
if(N == 0) return 0;
helper(N, N, new boolean[N + 1]);
return count;
}
private void helper(int N, int pos, boolean[] used) {
if(pos == 0){
count++;
return;
}
for(int i = N; i >= 1; i--){
if(!used[i] && (i % pos == 0 || pos % i == 0)){
used[i] = true;
helper(N, pos - 1, used);
used[i] = false;
}
}
}
}
进一步优化,用swap函数代替used。好处是完全避免了是否重复的判断,效率更高
public class Solution {
private int count = 0;
public int countArrangement(int N) {
if(N == 0) return 0;
int[] nums = new int[N + 1];
for(int i = 0; i <= N; i++) nums[i] = i;
helper(nums, N);
return count;
}
private void helper(int[] nums, int start) {
if(start == 0){
count++;
return;
}
for(int i = start; i >= 1; i--){
swap(nums, i, start);
if(nums[start] % start == 0 || start % nums[start] == 0) helper(nums, start - 1);
swap(nums, i, start);
}
}
private void swap(int[] nums, int i, int j)
{
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}