Skip to content

Latest commit

 

History

History

0634.Find the Derangement of An Array

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

English Version

题目描述

在组合数学中,如果一个排列中所有元素都不在原先的位置上,那么这个排列就被称为 错位排列

给定一个从 1n 升序排列的数组,返回 不同的错位排列 的数量 。由于答案可能非常大,你只需要将答案对 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]$。注意答案的取模操作。

我们发现,状态转移方程中只与 $f[i - 1]$$f[i - 2]$ 有关,因此我们可以使用两个变量 $a$$b$ 来分别表示 $f[i - 1]$$f[i - 2]$,从而将空间复杂度降低到 $O(1)$

时间复杂度 $O(n)$,空间复杂度 $O(1)$。其中 $n$ 为数组的长度。

Python3

class Solution:
    def findDerangement(self, n: int) -> int:
        mod = 10**9 + 7
        f = [1] + [0] * n
        for i in range(2, n + 1):
            f[i] = (i - 1) * (f[i - 1] + f[i - 2]) % mod
        return f[n]
class Solution:
    def findDerangement(self, n: int) -> int:
        mod = 10**9 + 7
        a, b = 1, 0
        for i in range(2, n + 1):
            a, b = b, ((i - 1) * (a + b)) % mod
        return b

Java

class Solution {
    public int findDerangement(int n) {
        long[] f = new long[n + 1];
        f[0] = 1;
        final int mod = (int) 1e9 + 7;
        for (int i = 2; i <= n; ++i) {
            f[i] = (i - 1) * (f[i - 1] + f[i - 2]) % mod;
        }
        return (int) f[n];
    }
}
class Solution {
    public int findDerangement(int n) {
        final int mod = (int) 1e9 + 7;
        long a = 1, b = 0;
        for (int i = 2; i <= n; ++i) {
            long c = (i - 1) * (a + b) % mod;
            a = b;
            b = c;
        }
        return (int) b;
    }
}

C++

class Solution {
public:
    int findDerangement(int n) {
        long long f[n + 1];
        memset(f, 0, sizeof(f));
        f[0] = 1;
        const int mod = 1e9 + 7;
        for (int i = 2; i <= n; i++) {
            f[i] = (i - 1LL) * (f[i - 1] + f[i - 2]) % mod;
        }
        return f[n];
    }
};
class Solution {
public:
    int findDerangement(int n) {
        long long a = 1, b = 0;
        const int mod = 1e9 + 7;
        for (int i = 2; i <= n; ++i) {
            long long c = (i - 1) * (a + b) % mod;
            a = b;
            b = c;
        }
        return b;
    }
};

Go

func findDerangement(n int) int {
	f := make([]int, n+1)
	f[0] = 1
	const mod = 1e9 + 7
	for i := 2; i <= n; i++ {
		f[i] = (i - 1) * (f[i-1] + f[i-2]) % mod
	}
	return f[n]
}
func findDerangement(n int) int {
	a, b := 1, 0
	const mod = 1e9 + 7
	for i := 2; i <= n; i++ {
		a, b = b, (i-1)*(a+b)%mod
	}
	return b
}

...