返回

LeetCode 2320.房屋放置数量计数器(Python实现)

后端

引言

LeetCode 2320 题要求我们计算在一条空旷的街道上放置房屋的不同方式。街道上有 n 块空地,每块空地上最多可以放置一所房屋。相邻两所房屋之间必须留有一块空地。

暴力 DFS 解法

最直接的解法是暴力 DFS。我们从第一块空地开始,枚举是放置房屋还是跳过该空地。对于每个选择,我们递归地探索后续的空地。

def count_ways_dfs(n):
    # 返回在 n 块空地上放置房屋的不同方式
    if n == 0:
        return 1
    if n < 0:
        return 0
    return count_ways_dfs(n - 1) + count_ways_dfs(n - 2)

记忆化 DFS 解法

暴力 DFS 存在大量重复计算。我们可以使用记忆化来优化它。

def count_ways_dfs_memo(n):
    memo = {}  # 存储已计算的结果
    return count_ways_dfs_memo_helper(n, memo)

def count_ways_dfs_memo_helper(n, memo):
    if n == 0:
        return 1
    if n < 0:
        return 0
    if n in memo:
        return memo[n]
    memo[n] = count_ways_dfs_memo_helper(n - 1, memo) + count_ways_dfs_memo_helper(n - 2, memo)
    return memo[n]

动态规划解法

动态规划可以进一步优化记忆化 DFS。我们从第一块空地开始,逐步计算放置房屋的不同方式,直到达到第 n 块空地。

def count_ways_dp(n):
    dp = [0] * (n + 1)  # dp[i] 表示前 i 块空地放置房屋的不同方式
    dp[0] = 1
    dp[1] = 1
    for i in range(2, n + 1):
        dp[i] = dp[i - 1] + dp[i - 2]
    return dp[n]

压缩状态动态规划解法

动态规划可以进一步压缩状态,仅存储当前和前一个状态。

def count_ways_dp_compressed(n):
    prev_prev = 1  # 前两个状态
    prev = 1  # 前一个状态
    for _ in range(2, n + 1):
        curr = prev_prev + prev  # 当前状态
        prev_prev = prev  # 更新前两个状态
        prev = curr  # 更新前一个状态
    return curr

Python 实现

以下是上述算法的 Python 实现:

import time

def count_ways_dfs(n):
    # 返回在 n 块空地上放置房屋的不同方式
    if n == 0:
        return 1
    if n < 0:
        return 0
    return count_ways_dfs(n - 1) + count_ways_dfs(n - 2)

def count_ways_dfs_memo(n):
    memo = {}  # 存储已计算的结果
    return count_ways_dfs_memo_helper(n, memo)

def count_ways_dfs_memo_helper(n, memo):
    if n == 0:
        return 1
    if n < 0:
        return 0
    if n in memo:
        return memo[n]
    memo[n] = count_ways_dfs_memo_helper(n - 1, memo) + count_ways_dfs_memo_helper(n - 2, memo)
    return memo[n]

def count_ways_dp(n):
    dp = [0] * (n + 1)  # dp[i] 表示前 i 块空地放置房屋的不同方式
    dp[0] = 1
    dp[1] = 1
    for i in range(2, n + 1):
        dp[i] = dp[i - 1] + dp[i - 2]
    return dp[n]

def count_ways_dp_compressed(n):
    prev_prev = 1  # 前两个状态
    prev = 1  # 前一个状态
    for _ in range(2, n + 1):
        curr = prev_prev + prev  # 当前状态
        prev_prev = prev  # 更新前两个状态
        prev = curr  # 更新前一个状态
    return curr

def main():
    n = int(input("请输入空地数量:"))

    # 开始计时
    start_time = time.time()

    # 运行算法
    result_dfs = count_ways_dfs(n)
    result_dfs_memo = count_ways_dfs_memo(n)
    result_dp = count_ways_dp(n)
    result_dp_compressed = count_ways_dp_compressed(n)

    # 结束计时
    end_time = time.time()

    # 输出结果
    print("暴力 DFS 解法:", result_dfs)
    print("记忆化 DFS 解法:", result_dfs_memo)
    print("动态规划解法:", result_dp)
    print("压缩状态动态规划解法:", result_dp_compressed)
    print("执行时间:", end_time - start_time, "秒")

if __name__ == "__main__":
    main()

性能分析

以下是对不同算法的性能分析:

算法 时间复杂度 空间复杂度
暴力 DFS O(2^n) O(n)
记忆化 DFS O(n) O(n)
动态规划 O(n) O(n)
压缩状态动态规划 O(n) O(1)

结论

通过逐步优化,我们从暴力 DFS 解法过渡到简洁高效的压缩状态动态规划解法。本文详细阐述了斐波那契数列在实际问题中的应用,并提供了不同算法的 Python 实现。