Advertisement

Beautiful Arrangement - LeetCode 526 Solution

Beautiful Arrangement - Complete Solution Guide

Beautiful Arrangement is LeetCode problem 526, a Medium level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.

Problem Statement

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 di

Detailed Explanation

The problem asks us to find the number of 'beautiful arrangements' of integers from 1 to `n`. A beautiful arrangement is a permutation of these numbers such that for each position `i` in the permutation, either the number at that position (`perm[i]`) is divisible by `i`, or `i` is divisible by the number at that position. Essentially, we need to count how many permutations satisfy this divisibility condition for all indices from 1 to `n`. The input is a single integer `n` (1 <= n <= 15), and the output is the number of beautiful arrangements.

Solution Approach

The provided solutions use a backtracking approach to explore all possible permutations. The core idea is to build the arrangement recursively, one position at a time. For each position, we try placing all available numbers (those not yet used). We check if the divisibility condition is satisfied. If it is, we mark the number as used, recursively call the backtracking function to fill the next position, and then unmark the number as used (backtracking step) to explore other possibilities. The base case for the recursion is when we have filled all positions (pos > n), at which point we have found a valid beautiful arrangement, and we increment the count.

Step-by-Step Algorithm

  1. Step 1: Initialize a `used` boolean array of size `n+1` to keep track of which numbers have already been placed in the arrangement. Initially, all values are false, meaning no numbers have been used.
  2. Step 2: Define a recursive function `backtrack(pos)` which represents the current position we are trying to fill in the arrangement (ranging from 1 to `n`).
  3. Step 3: Base Case: If `pos` is greater than `n`, it means we have filled all positions from 1 to `n` successfully. In this case, we have found a beautiful arrangement, so we return 1.
  4. Step 4: Iterate through numbers from 1 to `n`. For each number `num`, check if it has not been used yet (`used[num] == false`).
  5. Step 5: If the number is not used, check if the divisibility condition holds: either `num % pos == 0` or `pos % num == 0`.
  6. Step 6: If both conditions (not used and divisibility) are true, mark the number as used (`used[num] = true`).
  7. Step 7: Recursively call `backtrack(pos + 1)` to fill the next position. Add the result of this recursive call to the `count`. This explores all possible arrangements starting with the number 'num' at position 'pos'.
  8. Step 8: After the recursive call returns, unmark the number (`used[num] = false`). This is the backtracking step, allowing us to explore other possibilities for the current position.
  9. Step 9: After iterating through all numbers, return the accumulated `count`, which represents the number of beautiful arrangements that can be formed starting from the current position.
  10. Step 10: The main function `countArrangement(n)` initializes the `used` array and calls the `backtrack(1)` function to start the process from the first position (pos = 1). It then returns the final count.

Key Insights

  • Insight 1: Backtracking is suitable because we need to explore all possible permutations of numbers from 1 to n.
  • Insight 2: The small constraint of n <= 15 makes backtracking feasible, as the number of permutations grows factorially, but is still manageable within this limit.
  • Insight 3: Using a 'used' array (or similar data structure) is crucial to avoid reusing numbers in a permutation and ensure that each arrangement is a valid permutation.

Complexity Analysis

Time Complexity: O(n!)

Space Complexity: O(n)

Topics

This problem involves: Array, Dynamic Programming, Backtracking, Bit Manipulation, Bitmask.

Companies

Asked at: Cisco, HashedIn, MathWorks, Salesforce, UBS.