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 by i.i is divisible by perm[i].Given an integer n, return the number of the beautiful arrangements that you can construct.
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 <= 15When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to this problem is to simply try out every single possible arrangement of the numbers. We will check if each arrangement meets the 'beautiful' criteria. By trying every possibility, we guarantee we will find all valid arrangements.
Here's how the algorithm would work step-by-step:
def beautiful_arrangement_brute_force(number):
count = 0
numbers = list(range(1, number + 1))
def backtrack(index, available_numbers):
nonlocal count
# If we've used all numbers,
# check if arrangement is valid
if index == number:
count += 1
return
for current_number in available_numbers:
# Create a new list of available
# numbers for the next recursive step
remaining_numbers = available_numbers[:]
remaining_numbers.remove(current_number)
# Check the beautiful arrangement condition
# before continuing down the recursion
if (current_number % (index + 1) == 0) or \
((index + 1) % current_number == 0):
# Recursively build the arrangement
backtrack(index + 1, remaining_numbers)
# Start the backtracking with an index of 0
# and all numbers available
backtrack(0, numbers)
return countThe goal is to count special ways to arrange numbers. Instead of checking every single arrangement, we use a smart, step-by-step strategy. This involves figuring out which numbers can fit together based on the given rule and counting the possibilities efficiently.
Here's how the algorithm would work step-by-step:
def beautiful_arrangement(number): total_arrangements = 0
available_numbers = list(range(1, number + 1))
def count_arrangements(current_position, remaining_numbers):
nonlocal total_arrangements
# We found a valid arrangement
if not remaining_numbers:
total_arrangements += 1
return
# Iterate through the remaining numbers to find a suitable choice
for index, number_to_place in enumerate(remaining_numbers):
# Check divisibility condition. We only proceed if the
# condition is met, backtracking otherwise.
if (number_to_place % current_position == 0) or \
(current_position % number_to_place == 0):
# Create a new list excluding the selected number
next_remaining_numbers = remaining_numbers[:index] + remaining_numbers[index+1:]
# Recursively continue to the next position
count_arrangements(current_position + 1, next_remaining_numbers)
# Kick off the recursive process
count_arrangements(1, available_numbers)
return total_arrangements| Case | How to Handle |
|---|---|
| n = 0 | Return 0 or 1 (depending on the specific problem definition) if n is zero as there are no possible arrangements. |
| n = 1 | Return 1 because there is one possible arrangement: [1]. |
| n is a large number (scalability) | Be mindful of recursion depth, which can lead to stack overflow errors; memoization or dynamic programming can improve efficiency for larger n. |
| Inputs with only even or odd numbers for large n. | The recursive function may need to explore a large number of invalid states before discovering a solution; memoization can mitigate this. |
| Integer overflow for very large n in calculations. | Use appropriate data types (e.g., long) or modular arithmetic if intermediate results can exceed integer limits. |
| Cases where no valid solution exists (very rare, but theoretically possible) | Ensure the algorithm doesn't enter an infinite loop attempting to find a solution when none exists, and that it handles this gracefully. |
| Inputs where the initial permutation leads to early pruning | Consider strategies to explore more promising permutations early on, possibly through heuristic ordering. |
| Language specific stack overflow with deep recursion | Consider iterative solution or tail call optimization if supported, otherwise limit the depth of the recursion. |