leetcode
leetcode 1051 ~ 1100
不相交的握手

不相交的握手

难度:

标签:

题目描述

代码结果

运行时间: 32 ms, 内存: 16.1 MB


/*
 * Leetcode Problem 1259: Handshakes That Don't Cross
 * 
 * Problem Statement:
 * You are given an even number of people standing in a circle. Each person shakes hands with exactly one other person such that the handshakes do not cross. Determine the number of ways these handshakes can occur.
 * 
 * Approach:
 * This problem can be solved using dynamic programming with the help of Java Streams. We can use the concept of Catalan numbers which count the number of ways to correctly match parentheses, or in this case, the number of ways to arrange handshakes.
 * 
 * The recurrence relation for Catalan numbers is:
 * C(n) = sum(C(i) * C(n-1-i)) for i from 0 to n-1
 * 
 * In this problem, we are asked to find the number of ways to arrange handshakes for 2n people.
 */

import java.util.stream.IntStream;

public class HandshakesThatDontCrossStream {
    public int numberOfWays(int numPeople) {
        if (numPeople % 2 != 0) return 0;
        int n = numPeople / 2;
        long[] dp = new long[n + 1];
        dp[0] = 1;
        IntStream.rangeClosed(1, n).forEach(i -> dp[i] = IntStream.range(0, i).mapToLong(j -> dp[j] * dp[i - 1 - j]).sum());
        return (int) dp[n];
    }

    public static void main(String[] args) {
        HandshakesThatDontCrossStream solution = new HandshakesThatDontCrossStream();
        int numPeople = 6; // Example input
        System.out.println(solution.numberOfWays(numPeople)); // Output should be 5
    }
}

解释

方法:

这个题解使用了卡特兰数的公式。卡特兰数是一系列自然数,广泛用于计算在各种情境中不相交结构的数量。在这个问题中,我们要找到不相交的握手方式数,这可以用卡特兰数来解决。卡特兰数的第n项可以用公式 C(n) = (2n)! / ((n + 1)! * n!) 来计算。这里,n是握手的对数,即总人数的一半。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
题解中提到使用卡特兰数公式来解决问题,能否详细解释为什么不相交的握手问题可以用卡特兰数来描述?
卡特兰数是用于解决多种组合计数问题的一种数列,特别是那些涉及递归结构或不交叉结构的问题。在不相交的握手问题中,有偶数个人围成一个圈,每个人必须与另一个人握手,且所有的握手线不能交叉。这个问题可以通过递归方法解决:选择一个人作为起始点,这个人可以选择圈中任何一个非相邻的人进行握手。假设选定的两个人之间有 2k 个人,外侧有 2(n-k-1) 个人。这两部分都必须独立地进行不相交的握手,而这正是卡特兰数的定义问题。因此,总的不相交握手方式可以通过卡特兰数来计算。
🦆
在计算卡特兰数时,题解使用了阶乘的方法,这种方法在数字很大时是否会遇到性能瓶颈?
是的,使用阶乘的方法计算卡特兰数在数字非常大时确实会遇到性能问题。首先,阶乘数值增长非常快,很快就会超出普通整数类型的存储范围,尽管使用了Python的内置bigint来解决这个问题。其次,计算大数的阶乘需要更多的CPU时间和内存。通常在实际应用中,计算大的卡特兰数会采用更优的算法,如用逐项除或者使用组合公式直接计算需要的项,而不是完全展开阶乘。
🦆
题解使用了模运算`(10**9 + 7)`来进行结果的返回,为什么选择这个特定的数值进行模运算?
模数`10**9 + 7`是一个常用的大质数,广泛用于算法竞赛和编程题目中,主要是为了防止结果过大导致溢出和减少计算时间。此外,使用质数作为模数还有一个好处,那就是在模这个质数时,大部分操作(如加法、乘法)都可以保持良好的性能,因为质数可以保证除了1和它本身外,没有其他数能整除它,这有助于在使用哈希表等数据结构时减少冲突。
🦆
卡特兰数的计算涉及到两次阶乘的除法,如何确保计算过程中不会出现除以零的异常?
在卡特兰数的计算公式 C(n) = (2n)! / ((n + 1)! * n!) 中,我们需要注意的是两次除法操作。首先,由于n是握手的对数,它必须是非负整数。在这种情况下,n和n+1的阶乘都是定义良好的,且不为零(即使n为0,0! = 1)。因此,除以n! 和 (n+1)! 是安全的,不会出现除以零的异常。在实际编程实现中,只要保证n是非负整数,就不会有除零错误发生。

相关问题