Java 中可见 K 根的重排木棍数量13 May 2025 | 5 分钟阅读 给定 n 根从 1 到 n 标记的棒子,我们必须将它们排成一行,使得从左边恰好可以看到 k 根棒子。如果一根棒子比它前面的所有棒子都高,则它是可见的。任务是计算满足此约束的有效排列的数量。 示例 1 输入: n = 3, k = 2 输出: 排列棒子的方法数:3 解释: 有三种有效的方法:(1, 3, 2)、(2, 3, 1) 和 (3, 1, 2),其中从左边恰好可以看到 2 根棒子。 示例 2 输入: n = 4, k = 2 输出: 排列棒子的方法数:11 解释: 将最长的棒子放在第一位固定了一个位置,剩下的棒子使用 dp[3][2] = 3 加上 (3 * dp[3][1] = 8) 来计算,总共 11 种方法。 示例 3 输入: n = 4, k = 3 输出: 排列棒子的方法数:6 解释: 最长的棒子必须放在第一位,剩下的棒子可以按 dp[3][2] = 3 种方式排列,或者 2 * dp[3][3] = 3 种方式,总共 6 种。 示例 4 输入: n = 5, k = 3 输出: 排列棒子的方法数:35 解释: 将最长的棒子放在第一位贡献 dp[4][2] = 11,将其插入其他位置会增加 4 * dp[4][3] = 24,总计 35 种方法。 方法 1:动态规划(自顶向下,带记忆化)自顶向下动态规划(记忆化)方法是计算排列 n 根棒子使得恰好 k 根可见的方法数。思路是将问题分解成更小的子问题,并将已计算过的结果存储起来,以避免重复计算。 算法步骤 1: 如果 n == k,则只有一种排列方式(所有棒子都必须按递增顺序排列)。 步骤 2: 如果 n == 0 或 k == 0,则无效,返回 0。 步骤 3: 递推关系 步骤 3.1: 将最长的棒子放在第一位:它总是可见的,因此剩余的 n-1 根棒子应该排列使得 k-1 根可见。这贡献了 dp(n-1, k-1) 种方法。 步骤 3.2: 将最长的棒子放在其他位置:最长的棒子不会增加可见棒子的数量。剩余的 n-1 根棒子排列使得恰好 k 根可见,并且我们可以将最长的棒子插入 (n-1) 个不同的位置。这贡献了 (n-1) * dp(n-1, k) 种方法。 dp(n, k) = dp(n − 1, k − 1) + (n − 1) × dp(n − 1, k) 步骤 4: 将结果存储在 HashMap 中以避免冗余计算。 步骤 5: 如果子问题 (n, k) 已经计算过,则返回其存储的值,而不是重新计算。 让我们在 Java 程序中实现上述步骤。 输出 Ways to arrange sticks: 3 复杂度时间复杂度: 程序的复杂度为 O(n x k)。这是因为每个 (n, k) 对最多计算一次并存储在 map 中。 空间复杂度: 程序的复杂度为 O(n x k)。这是因为递归 栈。 方法 2:自底向上动态规划自底向上 动态规划 (DP) 方法维护一个二维 DP 表 dp[n][k],其中 dp[i][j] 表示排列 i 根棒子使得从左边恰好可见 j 根的方法数。 算法步骤 1: 定义 dp[i][j] 它存储排列 i 根棒子且有 j 根可见的方法数。 步骤 2: 基本情况 步骤 2.1: dp[0][0] = 1 (空排列,没有可见棒子)。 步骤 2.2: dp[i][0] = 0 对于 i > 0 (非空排列中不可能有 0 根可见棒子)。 步骤 2.3: dp[i][i] = 1 (排列 i 根棒子使得所有棒子都可见只有一种方法)。 步骤 3: 递推关系 步骤 3.1: 将最长的棒子放在第一位(总是可见),将问题简化为 dp[i-1][j-1]。 步骤 3.2: 将最长的棒子放在其他位置,使其不可见。剩余的 (i-1) 根棒子应该排列使得 j 根可见,我们可以用 (i-1) * dp[i-1][j] 种方法来完成。 步骤 3.3: 公式:dp[i][j] = dp[i−1] [j−1] + (i−1) × dp[i−1] [j] 步骤 4: 迭代 i 和 j 以使用公式计算值。 步骤 5: 返回 dp[n][k] 作为最终结果。 让我们在 Java 程序中实现上述步骤。 输出 Ways to arrange sticks: 3 复杂度时间复杂度: 程序的复杂度为 O(n x k)。因为填充 dp 表需要 n x k 次操作。 空间复杂度: 程序的复杂度为 O(n x k)。因为我们使用了一个大小为 (n+1) x (k+1) 的二维 DP 表。 下一主题Java 中按对角线打印矩阵 |
查找岛屿数量问题是通常在顶级公司编码轮面试中提出的标准问题。该问题基于图论。在图论中,我们查找连通分量的数量。在此问题中,我们必须查找相同的数量。因此,在...
阅读 6 分钟
在计算机编程中,反转字符串是一项典型的挑战,可用于数据编码、涉及字符串操作的算法以及回文检测等活动。Java 提供了多种反转字符串的方法,从内置函数到使用循环的简单技术。在此...
阅读 6 分钟
在 Java 中,图形用户界面 (GUI) 在创建交互式应用程序方面起着至关重要的作用。GUI 编程的关键方面之一是布局管理器,它决定了组件如何在容器内排列。边框布局管理器就是这样一种布局管理器,它简化了...
阅读 4 分钟
Java 是一种流行的编程语言,被世界各地的开发人员用于构建各种应用程序。尽管 Java 流行且可靠,但 Java 程序容易出错和出现异常。Java 中最常见的异常之一是 ClassNotFoundException。在本文中,...
阅读 4 分钟
"URLify" 描述了用 %20(通常用于表示 URL 中的空格)替换字符串中每个空格的做法。当构建可能包含空格的字符串以在不允许实际空格的 URL 中使用时,这一点至关重要。什么是 URLify?"URLify" 是...
7 分钟阅读
在本文中,我们将研究 JAVA 编程语言中的异步调用。在文章的最后,我们将清晰地了解异步调用以及它与 JAVA 编程语言中的同步调用有何不同。首先,我们...
阅读 8 分钟
将一种类型的对象和变量转换为另一种类型的过程称为类型转换。当编译器在程序员的干预下自动执行转换时,称为隐式类型转换或自动类型提升。在隐式类型转换中,转换涉及较小的...
阅读 3 分钟
?在 Java 中,ArrayList 是一个广泛使用的数据结构,允许动态调整元素大小。当涉及到显示 ArrayList 的内容时,默认行为是用方括号括起来打印元素。但是,在某些情况下,您可能想要...
5 分钟阅读
Java 是一种多功能编程语言,以其管理各种数据结构的灵活性而闻名。Java 中的一个重要概念,称为 padding,在管理内存、成功对齐记录和优化统计处理方面起着至关重要的作用。在本节中,我们将讨论 padding...
5 分钟阅读
在 Java 中,切换字符串是指字符串中每个字符的大小写都被翻转。所有大写字母都变成小写,所有小写字母都变成大写。例如,如果输入字符串是 "HelloWorld",则切换其字符后的输出将是 "hELLOwORLD"。在本节中,...
阅读 4 分钟
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India