526. Beautiful Arrangement (Medium)
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 $$i_{th}$$ position (1 ≤ i ≤ N) in this array:
- The number at the $$i_{th}$$ position is divisible by i.
- i is divisible by the number at the $$i_{th}$$ position.
Now given N, how many beautiful arrangements can you construct?
Example 1:
Input: 2
Output: 2
Explanation:
The first beautiful arrangement is [1, 2]:
Number at the 1st position (i=1) is 1, and 1 is divisible by i (i=1).
Number at the 2nd position (i=2) is 2, and 2 is divisible by i (i=2).
The second beautiful arrangement is [2, 1]:
Number at the 1st position (i=1) is 2, and 2 is divisible by i (i=1).
Number at the 2nd position (i=2) is 1, and i (i=2) is divisible by 1.
Note:
- N is a positive integer and will not exceed 15.
Solution: Backtracking
Guess the reason is:
- Init, every number are in the right position: nums[i] == i; (index start from 1....)
- Then, if
nums[i]%n==0 || n%nums[i]==0
is true, theni % n || nums[n] % i
is also true, both situation indicates safe to swap. - And the swap keeps the property of that, so its no need to check the
"(vs[n-1]%(i+1))==0 || (i+1)%vs[n-1])"
. Just guess, hope someone can give a entire proof.
I think if you change for loop condition to
for (int i = n-1; i>=0; i--)
it makes me easier to understand cause it's actually verifying if the number could be divided by index while doing the permutation
version 1: 6ms
class Solution {
public:
int countArrangement(int N) {
vector<int> v;
for (int i = 1; i <= N; ++i) v.push_back(i);
return counts(N, v);
}
int counts(int n, vector<int>& v) {
if (n <= 0) return 1;
int cnt = 0;
for (int i = 0; i < n; ++i) {
if (v[i]%n==0 || n%v[i]==0) {
swap(v[i], v[n-1]);
cnt += counts(n-1, v);
swap(v[i], v[n-1]);
}
}
return cnt;
}
};
version 2: 166ms
class Solution {
void helper(int N, int num, vector<bool>& used) {
if (num > N) { ++cnt; return; }
for (int i = 1; i <= N; ++i) {
if (!used[i] && (i%num == 0 || num%i == 0)) {
used[i] = true;
helper(N, num+1, used);
used[i] = false;
}
}
}
public:
int countArrangement(int N) {
if (N == 0) return 0;
vector<bool> used(N+1, false);
helper(N, 1, used);
return cnt;
}
private:
int cnt = 0;
};