Given an integer n, find the number of permutations of {1, 2, ..., n} such that for every i (1 <= i <= n), i is divisible by perm[i] or perm[i] is divisible by i.
Since the answer may be large, return it modulo 109 + 7.
Example 1:
Input: n = 2 Output: 2 Explanation: The permutation [1,2] means that for every i (1 <= i <= 2): - perm[1] = 1, 1 is divisible by i (1) - perm[2] = 2, 2 is divisible by i (2) The permutation [2,1] means that for every i (1 <= i <= 2): - perm[1] = 2, 2 is divisible by i (1) - perm[2] = 1, i (2) is divisible by perm[2] (1)
Example 2:
Input: n = 3 Output: 8
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 way is to try every possible order of the numbers and see if it works. This means making all the different arrangements and checking each one to see if it fits our rule.
Here's how the algorithm would work step-by-step:
def number_of_self_divisible_permutations(numbers):
import itertools
number_of_valid_permutations = 0
all_permutations = list(itertools.permutations(numbers))
for permutation in all_permutations:
is_self_divisible = True
# Check each number to see if it's self-divisible
for index, number in enumerate(permutation):
position = index + 1
#If a number at any position is 0, skip since it will cause division by zero.
if number == 0:
is_self_divisible = False
break
# Check if the number divides evenly into its position.
if position % number != 0:
is_self_divisible = False
break
# Increment the count if the permutation is self-divisible.
if is_self_divisible:
number_of_valid_permutations += 1
return number_of_valid_permutationsTo efficiently count self-divisible permutations, we'll use a technique called dynamic programming along with bit manipulation. Instead of exhaustively generating every permutation, we'll build up solutions incrementally, remembering previously computed results to avoid redundant calculations. This approach leverages bit manipulation to represent which numbers have already been placed in the permutation, making the entire process very fast.
Here's how the algorithm would work step-by-step:
def number_of_self_divisible_permutations(number):
numbers = list(range(1, number + 1))
count = 0
memo = {}
def permute(index, remaining_numbers):
nonlocal count
if index == number:
count += 1
return
# Use tuple of remaining nums as key for memoization
remaining_numbers_tuple = tuple(remaining_numbers)
if (index, remaining_numbers_tuple) in memo:
return memo[(index, remaining_numbers_tuple)]
temp_count = 0
for current_number in remaining_numbers:
# Check divisibility before proceeding to prevent unnecessary computation
if current_number % (index + 1) == 0:
remaining_numbers_copy = remaining_numbers[:]
remaining_numbers_copy.remove(current_number)
permute(index + 1, remaining_numbers_copy)
memo[(index, remaining_numbers_tuple)] = temp_count
return temp_count
permute(0, numbers)
return count| Case | How to Handle |
|---|---|
| n = 0 | Since the problem specifies digits from 1 to n, if n is 0, there are no digits to permute, so the result should be 0. |
| n = 1 | For n=1, the only permutation is [1], and 1 is divisible by 1, so the count is 1. |
| n = 2 | For n=2, the permutations are [1, 2] and [2, 1]. 1 is divisible by 1 and 2 is divisible by 2 for [1,2], and 2 is divisible by 1 and 1 is not divisible by 2 for [2,1], so return 1. |
| Large n (e.g., n = 15) | The solution's time complexity should be carefully considered, as the number of permutations grows factorially, and memoization is critical. |
| n is a negative number | The problem statement defines n as an integer representing the range 1 to n, so negative values are invalid and return 0. |
| Input where no self-divisible permutations exist | The algorithm should correctly return 0 when no permutation satisfies the condition, such as a case where i isn't always divisible by the number at the ith position. |
| Integer Overflow | The count of permutations can grow very quickly, so using an appropriate data type (e.g., long in Java) to store the count is necessary to prevent integer overflow. |
| Recursion Depth Limits | For larger values of 'n' recursive solutions might hit the stack size limit. Consider iterative DFS with explicit stack or memoization to avoid exceeding recursion depth limits. |