如何优化楼梯砖块问题的Python代码以支持200-250的大输入值?
Let's break down what's going on with your current code and fix it to handle values up to 250 (and beyond!) smoothly.
First, Understand the Problem's Core
Your problem is actually a classic integer partitioning problem: we need to count the number of ways to split n into distinct positive integers where each subsequent number is smaller than the previous (this is identical to counting distinct partitions, since order doesn't matter—we can always sort them descending). The only twist is that single-step "stairs" (like just [6] for n=6) don't count, so we'll subtract 1 from the total distinct partition count at the end.
What's Wrong with Your Current Code?
Your recursive approach has a few key issues that cause slowdown for larger n:
- Inefficient memoization: You're storing full lists of partitions in
memoryinstead of just counting the number of valid combinations. Storing all those lists wastes memory and adds unnecessary overhead when you only need a count. - Overly complex recursive logic: The nested conditionals and loops create lots of redundant calculations, even with memoization. Your
recfunction tries to build partitions piecemeal but lacks a clear state definition, leading to repeated work. - Arbitrary
max_vallimit: Settingmax_val = 201breaks for n > 200, since you're artificially restricting the largest possible step size.
Better Optimized Approaches
Let's look at two reliable methods: a clean memoized recursive solution and an iterative dynamic programming solution (the fastest for large n).
1. Memoized Recursive Solution
We'll define a recursive function that counts the number of distinct partitions of remaining bricks, where each step is no larger than max_step. This is a standard, efficient way to model distinct partition counting.
from functools import lru_cache def count_stairs(n): # Count all distinct partitions of n @lru_cache(maxsize=None) def distinct_partitions(remaining, max_step): if remaining == 0: return 1 # Base case: one valid way to make 0 bricks (use nothing) if max_step == 0 or remaining < 0: return 0 # Two choices: include max_step, or don't include it include = distinct_partitions(remaining - max_step, max_step - 1) exclude = distinct_partitions(remaining, max_step - 1) return include + exclude total_distinct = distinct_partitions(n, n) # Subtract 1 to exclude the single-step "staircase" (e.g., [6] for n=6) return total_distinct - 1 # Test with your example: n=6 should return 3 print(count_stairs(6)) # Output: 3 print(count_stairs(100)) # Runs quickly print(count_stairs(250)) # No performance issues
Why This Works:
- Automatic memoization with
lru_cache: Python handles caching ofdistinct_partitions(remaining, max_step)results for us, so we never compute the same state twice. - Clear state tracking: Each recursive call only tracks what matters: how many bricks are left, and the largest allowed step size. This eliminates redundant calculations.
- No arbitrary limits: We start with
max_step = n, so we handle all valid step sizes for any input n.
2. Iterative Dynamic Programming Solution
If you prefer an iterative approach (sometimes faster for very large n, though the recursive version is already great), we can build a DP table where dp[i] represents the number of distinct partitions of i.
def count_stairs_dp(n): # dp[i] = number of distinct partitions of i dp = [0] * (n + 1) dp[0] = 1 # Base case: one way to make 0 bricks # Iterate over each possible step size k for k in range(1, n + 1): # Update dp for all values from k to n (since k can't make smaller numbers) for i in range(k, n + 1): dp[i] += dp[i - k] # Subtract 1 to exclude the single-step staircase return dp[n] - 1 # Test cases print(count_stairs_dp(6)) # 3 print(count_stairs_dp(100)) print(count_stairs_dp(250))
How This Works:
- We iterate over each possible step size
k. For eachk, we add the number of partitions ofi - ktodp[i]—this represents addingkto all valid partitions ofi - k(since we processkin increasing order, we ensure no duplicate steps). - This runs in O(n²) time, which is totally feasible for n=250 (250² = 62,500 operations—trivial for Python).
Verify with Your Example
For n=6:
- Total distinct partitions are 4:
[6], [5,1], [4,2], [3,2,1] - Subtract 1 to exclude the single-step
[6], giving 3—matches your example perfectly.
Why Your Original Memoization Failed
Your code tried to store actual partition lists instead of counts, making memoization inefficient. Additionally, your recursive function didn't track a clear, consistent state (like remaining bricks and max_step), so you weren't reusing computed results effectively. The approaches above fix both issues by focusing on counting rather than storing partitions, and using well-defined states for memoization.
内容的提问来源于stack exchange,提问作者Ishu Kumar

