当前位置: 首页 > article >正文

力扣面试题 39 - 三步问题 C语言解法

题目:

三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模1000000007。

示例1:

 输入:n = 3 
 输出:4
 说明: 有四种走法

示例2:

 输入:n = 5
 输出:13

提示:

  1. n范围在[1, 1000000]之间

思路:

  1. 找规律。写出n=1~5的情况,可以发现规律。
  2. f(n) = f(n - 1) + f(n - 2) + f(n - 3)
  3. 如果使用递归,可以完成题目,但时间效率过低,呈指数级,因此需要优化
  4. 采用动态规划的思想优化算法,关于动态规划可以看我的这一篇什么是动态规划?内含代码示例-CSDN博客

先上错误答案,该代码无法通过测试用例,会超过系统响应时间!

原因分析:

  • default 分支使用递归计算 waysToStep(n - 1) + waysToStep(n - 2) + waysToStep(n - 3),但没有优化。
  • 直接递归会导致重复计算,时间复杂度是指数级,效率非常低。
int waysToStep(int n) {
    int ret = 0;
    switch(n){
        case 1: ret = 1;break;
        case 2: ret = 2;break;
        case 3: ret = 4;break;
        default: 
        ret = waysToStep(n - 1) + waysToStep(n - 2) + waysToStep(n - 3);break;
    }
    return ret % 1000000007;
}

下面是正确答案

int waysToStep(int n) {
    if(n == 1) return 1;
    if(n == 2) return 2;
    if(n == 3) return 4;
    int dp[n + 1];
    dp[1] = 1;
    dp[2] = 2;
    dp[3] = 4;
    for(int i = 4; i <= n; i++){
        dp[i] = ((dp[i - 1] + dp[i - 2]) % 1000000007 + dp[i - 3]) % 1000000007;
    }
    return dp[n];
}

我猜可能有小伙伴会疑惑,为什么要取模1000000007这个数字呢?

1. 防止结果溢出

在计算过程中,随着 nnn 的增大,结果 f(n)的数值可能非常庞大,远超出普通整型数据类型(如 intlong)的存储范围。

  • 在 C 语言中,int 通常是 32 位,最大值为 2^31 − 1=2147483647

  • 若不取模,可能导致数值溢出,计算结果错误。

通过对 1000000007取模,可以确保每次计算结果保持在一个合理范围内,避免溢出。


2. 选择 1000000007是因为它是一个大质数

大质数作为模数有以下好处:

  1. 减少冲突:质数的取模运算分布更均匀,避免因模数的因子导致的结果冲突。

  2. 数学性质良好:在许多算法中(如组合数学、同余定理等),质数模数可以简化计算,尤其是涉及模逆元时。


3. 标准化常用值

  • 1000000007是编程竞赛和算法题目中一个非常常用的模数。这是因为:

    1. 它是大于 10^9 的最小质数,适合限制大规模运算。

    2. 被广泛使用后形成了一种“惯例”,便于代码复用。


4. 计算结果的独特性

取模操作保证了即使结果很大,其取模值仍然能唯一标识原始计算结果。因此它既能代表正确的计算结果,又不影响结果的相对大小关系。


http://www.kler.cn/a/453256.html

相关文章:

  • Linux:code:network:devinet_sysctl_forward;IN_DEV_FORWARD
  • 海格通信嵌入式面试题及参考答案
  • 华为管理变革之道:奋斗文化与活力
  • 横向项目三模态融合笔记
  • Ingress-Nginx Annotations 指南:配置要点全方面解读(上)
  • Git--tag标签远程管理
  • 遗传萤火虫算法的原理
  • 【Git】—— 代码版本控制工具git的安装及基本使用
  • 【C++动态规划】1458. 两个子序列的最大点积|1823
  • 深度解析DAPP开发 | 智能合约与业务应用
  • Bert各种变体——RoBERTA/ALBERT/DistillBert
  • 容器化平台Docker初识
  • 动态规划<五> 子数组问题(含对应LeetcodeOJ题)
  • 下载运行Vue开源项目vue-pure-admin
  • 如何利用AWS监听存储桶并上传到tg bot
  • 模型 易得性偏差
  • 漏洞扫描:网络安全的 “体检” 与 “防护指南”
  • 常用的数据结构的时间复杂度
  • 实现某海外大型车企(T)Cabin Wi-Fi 需求的概述 - 4
  • 某些iphone手机录音获取流stream延迟问题 以及 录音一次第二次不录音问题
  • Python调用Elasticsearch更新数据库
  • Linux | 零基础Ubuntu搭建JDK
  • ref 和 reactive 的用法和区别
  • 【再学javascript算法之美】前端面试频率比较高的基础算法题
  • 新浪微博C++面试题及参考答案
  • 穷举vs暴搜vs深搜vs回溯vs剪枝系列一>括号生成