Beautiful Arrangement
MediumUpdated: Aug 2, 2025
Practice on:
Problem
Suppose you have n integers labeled 1 through n. A permutation of those n integers perm (1-indexed) is considered a beautiful arrangement if for every i (1 <= i <= n), either of the following is true:
perm[i]is divisible byi.iis divisible byperm[i].
Given an integer n, return thenumber of the beautiful arrangements that you can construct.
Examples
Example 1
Input: n = 2
Output: 2
Explanation:
The first beautiful arrangement is [1,2]:
- perm[1] = 1 is divisible by i = 1
- perm[2] = 2 is divisible by i = 2
The second beautiful arrangement is [2,1]:
- perm[1] = 2 is divisible by i = 1
- i = 2 is divisible by perm[2] = 1
Example 2
Input: n = 1
Output: 1
Constraints
1 <= n <= 15
Solution
Method 1 – Backtracking with Bitmask
Intuition
The problem asks for the number of permutations where, for each position, the number at that position is divisible by its index or vice versa. Since n is small (≤ 15), we can use backtracking to try all possible arrangements efficiently. Using a bitmask helps us track which numbers have been used so far.
Approach
- Use a recursive function to try placing each unused number at the current position.
- For each position
i(starting from 1), iterate through all numbers from 1 ton. - If a number
numis not used and eithernum % i == 0ori % num == 0, place it at positioni. - Mark
numas used (using bitmask), recurse for the next position. - When all positions are filled, increment the answer.
- Backtrack by unmarking the number and continue.
- Return the total count.
Code
C++
class Solution {
public:
int countArrangement(int n) {
int ans = 0;
function<void(int, int)> dfs = [&](int pos, int mask) {
if (pos > n) {
ans++;
return;
}
for (int num = 1; num <= n; ++num) {
if (!(mask & (1 << num)) && (num % pos == 0 || pos % num == 0)) {
dfs(pos + 1, mask | (1 << num));
}
}
};
dfs(1, 0);
return ans;
}
};
Go
func countArrangement(n int) int {
ans := 0
var dfs func(int, int)
dfs = func(pos, mask int) {
if pos > n {
ans++
return
}
for num := 1; num <= n; num++ {
if mask&(1<<num) == 0 && (num%pos == 0 || pos%num == 0) {
dfs(pos+1, mask|(1<<num))
}
}
}
dfs(1, 0)
return ans
}
Java
class Solution {
int ans = 0;
public int countArrangement(int n) {
dfs(n, 1, 0);
return ans;
}
void dfs(int n, int pos, int mask) {
if (pos > n) {
ans++;
return;
}
for (int num = 1; num <= n; num++) {
if ((mask & (1 << num)) == 0 && (num % pos == 0 || pos % num == 0)) {
dfs(n, pos + 1, mask | (1 << num));
}
}
}
}
Kotlin
class Solution {
var ans = 0
fun countArrangement(n: Int): Int {
fun dfs(pos: Int, mask: Int) {
if (pos > n) {
ans++
return
}
for (num in 1..n) {
if ((mask and (1 shl num)) == 0 && (num % pos == 0 || pos % num == 0)) {
dfs(pos + 1, mask or (1 shl num))
}
}
}
dfs(1, 0)
return ans
}
}
Python
class Solution:
def countArrangement(self, n: int) -> int:
ans: int = 0
def dfs(pos: int, mask: int) -> None:
nonlocal ans
if pos > n:
ans += 1
return
for num in range(1, n + 1):
if not (mask & (1 << num)) and (num % pos == 0 or pos % num == 0):
dfs(pos + 1, mask | (1 << num))
dfs(1, 0)
return ans
Rust
impl Solution {
pub fn count_arrangement(n: i32) -> i32 {
fn dfs(n: i32, pos: i32, mask: i32, ans: &mut i32) {
if pos > n {
*ans += 1;
return;
}
for num in 1..=n {
if (mask & (1 << num)) == 0 && (num % pos == 0 || pos % num == 0) {
dfs(n, pos + 1, mask | (1 << num), ans);
}
}
}
let mut ans = 0;
dfs(n, 1, 0, &mut ans);
ans
}
}
TypeScript
class Solution {
countArrangement(n: number): number {
let ans = 0;
function dfs(pos: number, mask: number): void {
if (pos > n) {
ans++;
return;
}
for (let num = 1; num <= n; num++) {
if ((mask & (1 << num)) === 0 && (num % pos === 0 || pos % num === 0)) {
dfs(pos + 1, mask | (1 << num));
}
}
}
dfs(1, 0);
return ans;
}
}
Complexity
- ⏰ Time complexity:
O(n!)(since we try all permutations, but pruning reduces actual calls) - 🧺 Space complexity:
O(n)(recursion stack and bitmask)