634. 寻找数组的错位排列 🔒
题目描述
在组合数学中,如果一个排列中所有元素都不在原先的位置上,那么这个排列就被称为 错位排列 。
给定一个从 1
到 n
升序排列的数组,返回 不同的错位排列 的数量 。由于答案可能非常大,你只需要将答案对 109+7
取余 输出即可。
示例 1:
输入: n = 3 输出: 2 解释: 原始的数组为 [1,2,3]。两个错位排列的数组为 [2,3,1] 和 [3,1,2]。
示例 2:
输入: n = 2 输出: 1
提示:
1 <= n <= 106
解法
方法一:动态规划
我们定义 \(f[i]\) 表示长度为 \(i\) 的数组的错位排列的数量。初始时 \(f[0] = 1\), \(f[1] = 0\)。答案即为 \(f[n]\)。
对于长度为 \(i\) 的数组,我们考虑将数字 \(1\) 放在哪个位置,假设放在第 \(j\) 个位置,这里有 \(i-1\) 种选择,那么接下来数字 \(j\) 可以有两种选择:
- 放在第 \(1\) 个位置,那么剩下的 \(i - 2\) 个位置可以有 \(f[i - 2]\) 种错位排列,因此总共有 \((i - 1) \times f[i - 2]\) 种错位排列;
- 不放在第 \(1\) 个位置,那么相当于转化为了长度为 \(i - 1\) 的数组的错位排列,因此总共有 \((i - 1) \times f[i - 1]\) 种错位排列。
综上,我们有如下状态转移方程:
\[
f[i] = (i - 1) \times (f[i - 1] + f[i - 2])
\]
最终答案即为 \(f[n]\)。注意答案的取模操作。
时间复杂度 \(O(n)\),其中 \(n\) 为数组的长度。空间复杂度 \(O(1)\)。
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 8 9 10 11 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
1 2 3 4 5 6 7 8 9 |
|
方法二:动态规划(空间优化)
我们发现,状态转移方程中只与 \(f[i - 1]\) 和 \(f[i - 2]\) 有关,因此我们可以使用两个变量 \(a\) 和 \(b\) 来分别表示 \(f[i - 1]\) 和 \(f[i - 2]\),从而将空间复杂度降低到 \(O(1)\)。
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
1 2 3 4 5 6 7 8 |
|