The "Handshakes That Don't Cross" problem asks you to determine how many valid ways people can shake hands around a round table such that no two handshakes cross each other.
Specifically, given n
people (where n
is always even), each person must shake hands with exactly one other person. A handshake is represented by a straight line drawn between two people sitting around the table. Handshakes are considered non-crossing if no two handshake lines intersect inside the circle.
Your goal is, for a given even n
, to return the number of ways such non-crossing handshakes can be made.
Constraints:
n
is even and in the range 0 ≤ n ≤ 1000
Let's break down the problem conceptually:
n
people can be built from solutions to smaller subproblems.n/2
-th Catalan number gives the answer for n
people.Let's outline the algorithm step-by-step:
n
people, we want the number of non-crossing handshake pairings. For n = 0
, there is 1 way (no handshakes).
k
(where k
is even and between 2 and n
).k-2
people (between person 2 and person k-1
), and one with n-k
people (the rest).k
of the product of the number of ways to handshake in each group.dp[i]
denote the number of valid handshake pairings for i
people.dp[0] = 1
(no people, one way).i
: dp[i] = sum(dp[j] * dp[i-2-j])
for all even j
from 0 to i-2
.dp
array up to n
.dp[n]
as the answer.n
.
Let's walk through an example with n = 4
:
1 * 1 = 1
.1 * 1 = 1
.1 + 1 = 2
.
dp[4] = 2
.
Brute-force Approach:
n
.n+1
.i
up to n
, we sum over roughly i/2
terms.O(n^2)
.O(n)
for the DP array.n
up to 1000.
The "Handshakes That Don't Cross" problem is a classic example of recursive combinatorics and dynamic programming. The key insight is recognizing that the problem is equivalent to computing Catalan numbers, which count the number of valid non-crossing pairings. By breaking the problem into subproblems and using a DP array, we can efficiently compute the answer for large n
. This approach is elegant because it leverages mathematical properties and avoids brute-force enumeration.
class Solution:
def numberOfWays(self, num_people: int) -> int:
MOD = 10**9 + 7
n = num_people
dp = [0] * (n + 1)
dp[0] = 1
for i in range(2, n + 1, 2):
for j in range(0, i, 2):
dp[i] = (dp[i] + dp[j] * dp[i - 2 - j]) % MOD
return dp[n]
class Solution {
public:
int numberOfWays(int num_people) {
const int MOD = 1e9 + 7;
int n = num_people;
std::vector dp(n + 1, 0);
dp[0] = 1;
for (int i = 2; i <= n; i += 2) {
for (int j = 0; j <= i - 2; j += 2) {
dp[i] = (dp[i] + dp[j] * dp[i - 2 - j]) % MOD;
}
}
return (int)dp[n];
}
};
class Solution {
public int numberOfWays(int num_people) {
int MOD = 1000000007;
int n = num_people;
long[] dp = new long[n + 1];
dp[0] = 1;
for (int i = 2; i <= n; i += 2) {
for (int j = 0; j <= i - 2; j += 2) {
dp[i] = (dp[i] + dp[j] * dp[i - 2 - j]) % MOD;
}
}
return (int)dp[n];
}
}
var numberOfWays = function(num_people) {
const MOD = 1e9 + 7;
let n = num_people;
let dp = new Array(n + 1).fill(0);
dp[0] = 1;
for (let i = 2; i <= n; i += 2) {
for (let j = 0; j <= i - 2; j += 2) {
dp[i] = (dp[i] + dp[j] * dp[i - 2 - j]) % MOD;
}
}
return dp[n];
};