[LeetCode] Find the Derangement of An Array 找数组的错排
In combinatorial mathematics, a derangement is a permutation of the elements of a set, such that no element appears in its original position.
There's originally an array consisting of n integers from 1 to n in ascending order, you need to find the number of derangement it can generate.
Also, since the answer may be very large, you should return the output mod 109 + 7.
Example 1:
Input: 3
Output: 2
Explanation: The original array is [1,2,3]. The two derangements are [2,3,1] and [3,1,2].
Note:n is in the range of [1, 106].
这道题给了我们一个数组,让我们求其错排的个数,所谓错排就是1到n中的每个数字都不在其原有的位置上,全部打乱了,问能有多少种错排的方式。博主注意到了这道题又让对一个很大的数取余,而且每次那个很大的数都是109 + 7,为啥大家都偏爱这个数呢,有啥特别之处吗?根据博主之前的经验,这种结果很大很大的题十有八九都是用dp来做的,那么就建一个一维的dp数组吧,其中dp[i]表示1到i中的错位排列的个数。那么难点就是找递推公式啦,先从最简单的情况来看:
n = 1 时有 0 种错排
n = 2 时有 1 种错排 [2, 1]
n = 3 时有 2 种错排 [3, 1, 2], [2, 3, 1]
然后博主就在想知道了dp[2],能求出dp[3]吗,又在考虑是不是算加入数字3的情况的个数。结果左看右看发现没有啥特别的规律,又在想是不是有啥隐含的信息需要挖掘,还是没想出来。于是看了一眼标签,发现是Math,我的天,难道又是小学奥数的题?挣扎了半天最后还是放弃了,上网去搜大神们的解法。其实这道题是组合数学种的错排问题,是有专门的递归公式的。
我们来想n = 4时该怎么求,我们假设把4排在了第k位,这里我们就让k = 3吧,那么我们就把4放到了3的位置,变成了:
x x 4 x
我们看被4占了位置的3,应该放到哪里,这里分两种情况,如果3放到了4的位置,那么有:
x x 4 3
那么此时4和3的位置都确定了,实际上只用排1和2了,那么就相当于只排1和2,就是dp[2]的值,是已知的。那么再来看第二种情况,3不在4的位置,那么此时我们把4去掉的话,就又变成了:
x x x
这里3不能放在第3个x的位置,在去掉4之前,这里是移动4之前的4的位置,那么实际上这又变成了排1,2,3的情况了,就是dp[3]的值。
再回到最开始我们选k的时候,我们当时选了k = 3,其实k可以等于1,2,3,也就是有三种情况,所以dp[4] = 3 * (dp[3] + dp[2])。
那么递推公式也就出来了:
dp[i] = (i - 1) * (dp[i - 1] + dp[i - 2])
有了递推公式,代码就不难写了吧,参见代码如下:
解法一:
class Solution {
public:
int findDerangement(int n) {
if (n < ) return ;
vector<long long> dp(n + , );
dp[] = ; dp[] = ;
for (int i = ; i <= n; ++i) {
dp[i] = (dp[i - ] + dp[i - ]) * (i - ) % ;
}
return dp[n];
}
};
下面这种解法精简了空间,因为当前值只跟前两个值有关系,所以没必要保留整个数组,只用两个变量来记录前两个值,并每次更新一下就好了,参见代码如下:
解法二:
class Solution {
public:
int findDerangement(int n) {
long long a = , b = , res = ;
for (int i = ; i <= n; ++i) {
res = (i - ) * (a + b) % ;
a = b;
b = res;
}
return (n == ) ? : res;
}
};
下面这种方法是对之前的递推公式进行了推导变形,使其只跟前一个数有关,具体的推导步骤是这样的:
我们假设 e[i] = dp[i] - i * dp[i - 1]
递推公式为: dp[i] = (i - 1) * (dp[i - 1] + dp[i - 2])
将递推公式带入假设,得到:
e[i] = -dp[i - 1] + (n - 1) * dp[i - 2] = -e[i - 1]
从而得到 e[i] = (-1)^n
那么带回假设公式,可得: dp[i] = i * dp[i - 1] + (-1)^n
根据这个新的递推公式,可以写出代码如下:
解法三:
class Solution {
public:
int findDerangement(int n) {
long long res = ;
for (int i = ; i <= n; ++i) {
res = (i * res + (i % == ? : -)) % ;
}
return res;
}
};
参考资料:
https://discuss.leetcode.com/topic/94429/o-n-short-java-code
https://discuss.leetcode.com/topic/94767/java-dp-solution-with-explanation
https://discuss.leetcode.com/topic/94421/java-solution-with-explanation-by-using-staggered-formula
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Find the Derangement of An Array 找数组的错排的更多相关文章
- [LeetCode] Find All Duplicates in an Array 找出数组中所有重复项
Given an array of integers, 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others ...
- [LeetCode] Single Element in a Sorted Array 有序数组中的单独元素
Given a sorted array consisting of only integers where every element appears twice except for one el ...
- [LeetCode] Peak Index in a Mountain Array 山形数组的顶峰坐标
Let's call an array A a mountain if the following properties hold: A.length >= 3 There exists som ...
- LeetCode 977. Squares of a Sorted Array (有序数组的平方)
题目标签:Array 题目给了我们一组 从小到大的 integers,让我们平方数字 并且 也排序成 从小到达. 因为有负数在里面,平方后,负数在array的位置会变动. 可以设left 和 righ ...
- [LeetCode] 26. Remove Duplicates from Sorted Array 有序数组中去除重复项
Given a sorted array nums, remove the duplicates in-place such that each element appear only once an ...
- leetCode 26.Remove Duplicates from Sorted Array(删除数组反复点) 解题思路和方法
Remove Duplicates from Sorted Array Given a sorted array, remove the duplicates in place such that e ...
- [leetcode]26. Remove Duplicates from Sorted Array有序数组去重(单个元素只出现一次)
Given a sorted array nums, remove the duplicates in-place such that each element appear only once an ...
- [LeetCode] 80. Remove Duplicates from Sorted Array II 有序数组中去除重复项 II
Given a sorted array nums, remove the duplicates in-place such that duplicates appeared at most twic ...
- [leetcode]81. Search in Rotated Sorted Array II旋转过有序数组里找目标值II(有重)
This is a follow up problem to Search in Rotated Sorted Array, where nums may contain duplicates. 思路 ...
随机推荐
- java中的IO 的示例
字符流 package jd_1; import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileNot ...
- PHP 引用是个坑,请慎用
去年我参加了很多次会议,其中八次会议里我进行了相关发言,这其中我多次谈到了 PHP 的引用问题,因为很多人对它的理解有所偏差.在深入讨论这个问题之前,我们先回顾一下引用的基本概念,明确什么是" ...
- Vue中的v-cloak用法
v-cloak 的作用和用法 用法: 这个指令保持在元素上直到关联实例结束编译.和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Must ...
- JavaScript(第八天)【时间与日期】
ECMAScript提供了Date类型来处理时间和日期.Date类型内置一系列获取和设置日期时间信息的方法. 一.Date类型 ECMAScript中的Date类型是在早期Java中java.util ...
- IDEA配置Struts框架
对于刚接触编程的同学,对框架只是还不是很了解,本文主要介绍在Idea上配置Struts,实现简单的页面跳转,以及页面参数传递. 在进行代码编写之前先对Idea进行一个简单了解,对于长时间接触编程的,对 ...
- 高级软件工程2017第6次作业——团队项目:Alpha阶段综合报告
1.版本测试报告 1.1在测试过程中总共发现了多少Bug?每个类别的Bug分别为多少个? Bug分类 Bug内容 Fixed 编辑博文时改变文字格式会刷新界面 Can't reproduced 无 N ...
- 需求分析&原型设计
需求分析&原型设计 需求分析 访问软件项目真实用户 首先本项目的用户是这个需要做简单四则运算的用户(我们团队通过对家里有三四年级小学生(需要做简单四则运算)的简单采访):反映了几个主要的问题: ...
- 数字是否可以被3和5同时整除,use if and % (21.9.2017)
#include <stdio.h> int main(){ int a; //a是所输入的数字 printf("输入数字: "); scanf("%d&qu ...
- networkx 学习
import networkx as nx import pylab import numpy as np #自定义网络 row=np.array([,,,,,,]) col=np.array([,, ...
- 201621123044《JAVA程序设计》第一周学习总结
1. 本周学习总结 1.了解了JAVA的诞生以及发展历史简介.JAVA语言的特点,以及JAVA的电脑安装以及环境配置. 2.JAVA不仅可以用eclipse进行编写,也可以在记事本和notepad++ ...