LeetCode 1359. Count All Valid Pickup and Delivery Options【动态规划,组合数学】1722

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章中,我不仅会讲解多种解题思路及其优化,还会用多种编程语言实现题解,涉及到通用解法时更将归纳总结出相应的算法模板。

为了方便在PC上运行调试、分享代码文件,我还建立了相关的仓库。在这一仓库中,你不仅可以看到LeetCode原题链接、题解代码、题解文章链接、同类题目归纳、通用解法总结等,还可以看到原题出现频率和相关企业等重要信息。如果有其他优选题解,还可以一同分享给他人。

由于本系列文章的内容随时可能发生更新变动,欢迎关注和收藏征服LeetCode系列文章目录一文以作备忘。


给你 n 笔订单,每笔订单都需要快递服务。

请你统计所有有效的 收件/配送 序列的数目,确保第 i 个物品的配送服务 delivery(i) 总是在其收件服务 pickup(i) 之后。

由于答案可能很大,请返回答案对 10^9 + 7 取余的结果。

示例 1:

输入:n = 1
输出:1
解释:只有一种序列 (P1, D1),物品 1 的配送服务(D1)在物品 1 的收件服务(P1)后。

示例 2:

输入:n = 2
输出:6
解释:所有可能的序列包括:
(P1,P2,D1,D2)(P1,P2,D2,D1)(P1,D1,P2,D2)(P2,P1,D1,D2)(P2,P1,D2,D1)  (P2,D2,P1,D1)
(P1,D2,P2,D1) 是一个无效的序列,因为物品 2 的收件服务(P2)不应在物品 2 的配送服务(D2)之后。

示例 3:

输入:n = 3
输出:90

提示:

  • 1 <= n <= 500

解法 动态规划+组合数学+递推

f [ i ] f[i] f[i] 表示订单数量为 i 时的序列数目,我们希望通过 f [ 1 ] , f [ 2 ] , . . . , f [ i − 1 ] f[1], f[2], ..., f[i - 1] f[1],f[2],...,f[i1] 得到 f [ i ] f[i] f[i] 的值,这样就可以使用递推的方法得到 f [ n ] f[n] f[n] 了。

由于 f [ i ] f[i] f[i] 包含了 i i i 份订单,我们可以将其拆分为前 i − 1 i - 1 i1 份订单(编号为 1 , 2 , . . . , i − 1 1, 2, ..., i - 1 1,2,...,i1 )与 1 1 1 份额外的订单(编号为 i)。对于一个包含前 i − 1 i - 1 i1 份订单的固定序列,它的长度为 ( i − 1 ) ∗ 2 (i - 1) * 2 (i1)2 ,我们只需要在这个序列中加上第 i i i 份订单,就可以得到一条订单数量为 i i i 的序列。

那么有多少种不同的方法能够加上第 i i i 份订单呢?第 i 份订单包含 P i P_i Pi D i D_i Di ,并且 P i P_i Pi 在序列中必须出现在 D i D_i Di 之前,那么我们可以将这些方法分成两类:

  • 第一类: P i P_i Pi D i D_i Di 被添加到了序列中连续的位置。由于序列的长度为 ( i − 1 ) ∗ 2 (i - 1) * 2 (i1)2 ,那么可以添加的位置为序列的长度加 1 1 1 ,即 2 ( i − 1 ) + 1 = 2 i − 1 2(i - 1) + 1 = 2i - 1 2(i1)+1=2i1
  • 第二类: P i P_i Pi​ 和 D i D_i Di 被添加到了序列中不连续的位置,那么就相当于在 i ∗ 2 − 1 i * 2 - 1 i21 个位置中选择两个不同的位置,前者用作添加 P i P_i Pi ,后者用作添加 D i D_i Di ,方法数为组合数 ( 2 i − 1 2 ) = ( 2 i − 1 ) ( i − 1 ) \binom{2i - 1}{2} = (2i - 1)(i - 1) (22i1)=(2i1)(i1)

将这两类的方法数量相加,就可以得到:对于一个固定的包含前 i − 1 i - 1 i1 份订单的固定序列,用 ( 2 i − 1 ) i (2i-1)i (2i1)i 种方法可以加入第 i i i 份订单。由于前 i − 1 i - 1 i1 份订单对应的序列数目为 f [ i − 1 ] f[i - 1] f[i1] ,并且对于任意两个不同的包含前 i − 1 i - 1 i1 份订单的序列,都不会因为加上第 i i i 份订单使得它们变得相同。因此我们就得到了递推公式:
f [ i ] = ( 2 i − 1 ) i ∗ f [ i − 1 ] f[i] =(2i−1)i∗f[i−1] f[i]=(2i1)if[i1]
由于递推公式中 f [ i ] f[i] f[i] 仅与 f [ i − 1 ] f[i - 1] f[i1] 有关,我们在递推式可以只存储 f [ i − 1 ] f[i - 1] f[i1] 的值,而不用把 f [ 1 ] , f [ 2 ] , . . . , f [ i − 1 ] f[1], f[2], ..., f[i - 1] f[1],f[2],...,f[i1] 都记录下来。

using LL = long long;class Solution {
private:static constexpr int mod = 1000000007;
public:int countOrders(int n) {if (n == 1) return 1;int ans = 1;for (int i = 2; i <= n; ++i)ans = (LL)ans * (i * 2 - 1) % mod * i % mod;return ans;}
};

复杂度分析:

  • 时间复杂度: O ( N ) O(N) O(N)
  • 空间复杂度: O ( 1 ) O(1) O(1)

解法2 整体法

除了递推法之外,我们也可以从整体进行考虑,直接得到 f [ i ] f[i] f[i] 的通项公式。

假设现在没有 D i D_i Di 必须在 P i P_i Pi 之后的要求,那么
f [ i ] = ( 2 i ) ! f[i] =(2i)! f[i]=(2i)!
这是因为我们可以将 P 1 , D 1 , P 2 , D 2 , ⋯ , P i , D i P_1, D_1, P_2, D_2, \cdots, P_i, D_i P1,D1,P2,D2,,Pi,Di 的任意一个排列作为答案,排列的数目为 ( 2 i ) ! (2i)! (2i)! 。我们称这些排列为初始排列。

那么在加上了「 D i D_i Di 必须在 P i P_i Pi 之后」的要求后,有一些初始排列就不能作为答案了。但是我们可以对它们进行调整,使它们变成满足要求的排列。具体地,对于任意一个初始排列,如果第 j j j 个物品的 D j D_j Dj 出现在 P j P_j Pj 之前,那么我们就把 D j D_j Dj P j P_j Pj 交换顺序。在对 j = 1 , 2 , . . . , i j = 1, 2, ..., i j=1,2,...,i 全部判断一遍之后,我们就可以得到一个满足要求的排列了。然而这样会导致重复计数,这是因为不同的初始排列在交换顺序之后会得到相同的排列,例如当 i = 2 i = 2 i=2 时,初始排列
D 1 , D 2 , P 1 , P 2 D 1 , P 2 , P 1 , D 2 \begin{aligned}D1, D2, P1, P2 \\ D1, P2, P1, D2\end{aligned} D1,D2,P1,P2D1,P2,P1,D2
在交换后都会得到相同的排列 P 1 , P 2 , D 1 , D 2 P1, P2, D1, D2 P1,P2,D1,D2 如何去除重复计数呢?我们可以进行逆向思考,反过来计算一个排列可以从多少个初始排列得来。显然,对于排列中的 i i i P j P_j Pj D j D_j Dj ,我们将其中任意数量的对交换顺序,都可以得到一个不同的初始排列。交换顺序的选择有 2 i 2^i 2i 种(每一对 P j P_j Pj D j D_j Dj​ 交换或不交换),因此一个排列对应着 2 i 2^i 2i 个初始排列,即排列的数目为:
f [ i ] = ( 2 i ) ! 2 i f[i] = \frac{(2i)!}{2^i} f[i]=2i(2i)!

这样就得到了 f [ i ] f[i] f[i] 的通项公式。由于通项公式中包含除法,在取模的意义下不好直接计算,我们可以将分母 2 i 2^i 2i 拆分成 i i i 个 222,与分子阶乘中的 i i i 个偶数相除,得到
f [ i ] = i ! ( 2 i − 1 ) ! ! f[i] = i!(2i-1)!! f[i]=i!(2i1)!!
其中 ( 2 i − 1 ) ! ! = 1 ⋅ 3 ⋅ ⋯ ⋅ ( 2 i − 1 ) (2i-1)!! = 1 \cdot 3 \cdot \cdots \cdot (2i-1) (2i1)!!=13(2i1) ,其与方法一中的递推式是一致的,可以直接使用方法一的代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/108445.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

BGP路由属性

任何一条BGP路由都拥有多个路径属性&#xff08;Path Attributes&#xff09;&#xff0c;当路由器通告BGP路由给它的对等体时&#xff0c;该路由将会携带多个路径属性&#xff0c;这些属性描述了BGP路由的各项特征&#xff0c;同时在某些场景下也会影响BGP路由优选的决策。 一…

百度收录和权重怎么提升-网站如何获得百度权重

你是否一直苦恼于网站权重的低迷&#xff1f;不知道如何开始提升网站权重&#xff0c;缺乏优质内容更新网站。不清楚如何进行关键词优化来提升网站排名和权重。SEO是一个需要持续投入时间和资源的过程。每个网站的情况都会有所不同&#xff0c;因此所花费的时间也会有所差异。然…

Spring基础(2w字---学习总结版)

目录 一、Spirng概括 1、什么是Spring 2、什么是容器 3、什么是IoC 4、模拟实现IoC 4.1、传统的对象创建开发 5、理解IoC容器 6、DI概括 二、创建Spring项目 1、创建spring项目 2、Bean对象 2.1、创建Bean对象 2.2、存储Bean对象&#xff08;将Bean对象注册到容器…

Apollo介绍和入门

文章目录 Apollo介绍配置中心介绍apollo介绍主流配置中心功能特性对比 Apollo简介 入门简单的执行流程Apollo具体的执行流程Apollo对象执行流程分步执行流程 核心概念应用&#xff0c;环境&#xff0c;集群&#xff0c;命名空间企业部署方案灰度发布全量发布 配置发布的原理发送…

HCIE-HCS规划设计搭建

1、相关术语 1、等价路由 等价路由&#xff08;Equal-cost routing&#xff09;是一种网络路由策略&#xff0c;用于在网络中选择多个具有相同路由度量&#xff08;路由距离或成本&#xff09;的最佳路径之一来转发数据流量。 当存在多个路径具有相同的路由度量时&#xff0c;…

“系统的UI”——SystemUI

SystemUI的实现 以StatusBar为例&#xff0c;来分析下Android系统具体是如何实现它们的。 相关代码分为两部分&#xff0c;即&#xff1a; Service部分 代码路径&#xff1a;frameworks/base/services/java/com/android/server。 应用部分 代码路径&#xff1a;frameworks…

聚合物发光材料荧光量子效率测量

近年来‚聚合物发光材料与器件受到人们的极大关注和高度重视‚其关键是聚合物发光器件具有光吸收范围宽‚吸收强度大‚发光效率高‚激发阈值低以及制备工艺简便灵活等显著特点‚已成为有机固体激光领域一个新的研究热点。 现有的聚合物发光材料体系主要集中在&#xff1a;聚噻…

【环境配置】基于Docker配置Chisel-Bootcamp环境

文章目录 Chisel是什么Chisel-Bootcamp是什么基于Docker配置Chisel-Bootcamp官网下载Docker安装包Docker换源启动Bootcamp镜像常用docker命令 可能产生的问题 Chisel是什么 Chisel是Scala语言的一个库&#xff0c;可以由Scala语言通过import引入。 Chisel编程可以生成Verilog代…

mysql文档--innodb中的重头戏--事务隔离级别!!!!--举例学习--现象演示

阿丹&#xff1a; 先要说明一点就是在网上现在查找的mysql中的事务隔离级别其实都是在innodb中的事务隔离级别。因为在mysql的5.5.5版本后myisam被innodb打败&#xff0c;从此innodb成为了mysql中的默认存储引擎。所以在网上查找的事务隔离级别基本上都是innodb的。并且支持事务…

数据结构 > 算法的时间复杂度(1)

目录 1.算法效率 1.1如何衡量一个算法的好坏 1.2算法的复杂度 1.3复杂度在校招中的考察 2.时间复杂度 2.1时间复杂度的概念 2.2大O的渐进表示法 2.3特殊情况 1.算法效率 1.1如何衡量一个算法的好坏 如何衡量一个算法的好坏呢&#xff1f;比如对于以下斐波那契数列&…

qiankun 子应用 ant-design-vue快速填坑指南

qiankun 子应用使用 ant-design-vue v3 问题 Cascader无法显示下拉Form label 显示混乱Message 提示报错等各种样式不兼容问题… 解决办法 子应用 ant-design-vue v3 升v4 官网文档子应用 ant-design-vue ConfigProvider prefixCls全局化修改 设置统一样式前缀&#xff0c;…

【AI】机器学习——线性模型(线性回归)

线性模型既能体现出重要的基本思想&#xff0c;又能构造出功能更加强大的非线性模型 参考&#xff1a;唐宇迪机器学习课程 文章目录 3.1 线性模型3.1.1 数据3.1.2 目标/应用 3.2 线性回归3.2.1 回归模型历史3.2.2 回归分析研究内容回归分析步骤 3.2.3 回归分析分类3.2.4 回归模…