Skip to content

Files

Latest commit

9a7c8ed · Mar 3, 2023

History

History
187 lines (144 loc) · 4.5 KB

File metadata and controls

187 lines (144 loc) · 4.5 KB

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 ) × f [ i 2 ] 种错位排列;
  • 不放在第 1 个位置,那么相当于转化为了长度为 i 1 的数组的错位排列,因此总共有 ( i 1 ) × f [ i 1 ] 种错位排列。

综上,我们有如下状态转移方程:

f [ i ] = ( i 1 ) × ( 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
}

...