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

C/C++蓝桥杯算法真题打卡(Day2)

一、面试题 08.01. 三步问题 - 力扣(LeetCode)

算法代码:

class Solution {
public:
    const int MOD = 1e9 + 7;
    int waysToStep(int n) {
        // 1. 创建 dp 表
        // 2. 初始化
        // 3. 填表
        // 4. 返回
        // 处理边界情况
        if (n == 1 || n == 2)
            return n;
        if (n == 3)
            return 4;
        vector<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]) % MOD + dp[i - 3]) % MOD;
        return dp[n];
    }
};

        这段代码的目的是计算上楼梯的方式数,每次可以走1步、2步或3步。代码使用了动态规划(DP)来解决这个问题。下面是代码的详细思路:

1. 创建 DP 表

  • 使用一个数组 dp 来存储每个台阶对应的上楼梯方式数。

  • dp[i] 表示上到第 i 个台阶的方式数。

2. 初始化

  • 对于前三个台阶,直接初始化:

    • dp[1] = 1:只有一种方式(走1步)。

    • dp[2] = 2:有两种方式(1+1 或 2)。

    • dp[3] = 4:有四种方式(1+1+1, 1+2, 2+1, 3)。

3. 填表

  • 从第4个台阶开始,每个台阶的方式数等于前三个台阶方式数的和:

    • dp[i] = dp[i-1] + dp[i-2] + dp[i-3]

  • 由于结果可能非常大,每次计算后都对 MOD 取模,防止溢出。

4. 返回结果

  • 最终返回 dp[n],即上到第 n 个台阶的方式数。

边界情况处理

  • 如果 n 是1、2或3,直接返回对应的值,避免不必要的计算。

代码优化

  • 由于每次只需要前三个状态,可以优化空间复杂度,使用三个变量代替整个 dp 数组。

优化后的代码

class Solution {
public:
    const int MOD = 1e9 + 7;
    int waysToStep(int n) {
        if (n == 1 || n == 2)
            return n;
        if (n == 3)
            return 4;
        
        int a = 1, b = 2, c = 4; // 分别代表 dp[i-3], dp[i-2], dp[i-1]
        int result = 0;
        for (int i = 4; i <= n; i++) {
            result = ((a + b) % MOD + c) % MOD;
            a = b;
            b = c;
            c = result;
        }
        return result;
    }
};

优化思路

  • 使用三个变量 abc 来存储前三个状态,减少空间复杂度。

  • 每次更新 result 后,滚动更新 abc 的值。

这样,代码的空间复杂度从 O(n) 降低到了 O(1),同时保持了时间复杂度的 O(n)

二、5. 最长回文子串 - 力扣(LeetCode)

算法代码:

class Solution {
public:
    string longestPalindrome(string s) {
        // 中⼼扩展算法
        int begin = 0, len = 0, n = s.size();
        for (int i = 0; i < n; i++) // 依次枚举所有的中点
        {
            // 先做⼀次奇数⻓度的扩展
            int left = i, right = i;
            while (left >= 0 && right < n && s[left] == s[right]) {
                left--;
                right++;
            }
            if (right - left - 1 > len) {
                begin = left + 1;
                len = right - left - 1;
            }
            // 偶数⻓度的扩展
            left = i, right = i + 1;
            while (left >= 0 && right < n && s[left] == s[right]) {
                left--;
                right++;
            }
            if (right - left - 1 > len) {
                begin = left + 1;
                len = right - left - 1;
            }
        }
        return s.substr(begin, len);
    }
};

         这段代码的目的是找到字符串 s 中的最长回文子串。它使用了中心扩展算法,通过枚举每个可能的中心点,向左右扩展,找到最长的回文子串。以下是代码的详细思路:


1. 中心扩展算法的核心思想

  • 回文串可以分为两种:

    • 奇数长度:中心是一个字符(例如 "aba")。

    • 偶数长度:中心是两个字符(例如 "abba")。

  • 通过枚举每个可能的中心点,向左右扩展,找到以该中心点为基准的最长回文子串。


2. 代码实现思路

变量说明

  • begin:记录最长回文子串的起始位置。

  • len:记录最长回文子串的长度。

  • n:字符串 s 的长度。

步骤

  1. 枚举所有可能的中心点

    • 遍历字符串 s,每个字符 s[i] 都可能是回文串的中心点。

  2. 奇数长度的扩展

    • 初始化 left 和 right 为当前中心点 i

    • 向左右扩展,检查 s[left] 和 s[right] 是否相等。

    • 如果相等,继续扩展;否则停止。

    • 计算当前回文子串的长度 right - left - 1,如果比 len 大,则更新 begin 和 len

  3. 偶数长度的扩展

    • 初始化 left 为 iright 为 i + 1(表示中心是两个字符)。

    • 向左右扩展,检查 s[left] 和 s[right] 是否相等。

    • 如果相等,继续扩展;否则停止。

    • 计算当前回文子串的长度 right - left - 1,如果比 len 大,则更新 begin 和 len

  4. 返回结果

    • 使用 s.substr(begin, len) 截取最长回文子串并返回。


3. 代码优化

  • 时间复杂度O(n^2),其中 n 是字符串的长度。每个中心点最多扩展 n 次。

  • 空间复杂度O(1),只使用了常数级别的额外空间。


4. 优化后的代码

class Solution {
public:
    string longestPalindrome(string s) {
        int begin = 0, len = 0, n = s.size();
        for (int i = 0; i < n; i++) {
            // 奇数长度扩展
            int l = i, r = i;
            expandAroundCenter(s, l, r, begin, len);
            // 偶数长度扩展
            l = i, r = i + 1;
            expandAroundCenter(s, l, r, begin, len);
        }
        return s.substr(begin, len);
    }

private:
    void expandAroundCenter(const string& s, int l, int r, int& begin, int& len) {
        while (l >= 0 && r < s.size() && s[l] == s[r]) {
            l--;
            r++;
        }
        int currentLen = r - l - 1;
        if (currentLen > len) {
            begin = l + 1;
            len = currentLen;
        }
    }
};

5. 优化思路

  • 将奇数长度和偶数长度的扩展逻辑提取到一个单独的函数 expandAroundCenter 中,避免代码重复。

  • 通过传递 begin 和 len 的引用,直接更新最长回文子串的起始位置和长度。


6. 示例运行

输入:

string s = "babad";
Solution sol;
cout << sol.longestPalindrome(s); // 输出 "bab" 或 "aba"

运行过程:

  1. 枚举中心点 i

    • i = 0:奇数扩展得到 "b",偶数扩展得到 ""

    • i = 1:奇数扩展得到 "bab",偶数扩展得到 ""

    • i = 2:奇数扩展得到 "aba",偶数扩展得到 ""

    • i = 3:奇数扩展得到 "a",偶数扩展得到 ""

    • i = 4:奇数扩展得到 "d",偶数扩展得到 ""

  2. 最终最长回文子串为 "bab" 或 "aba"


7. 总结

  • 中心扩展算法是一种直观且高效的方法,适用于解决最长回文子串问题。

  • 通过优化代码结构,可以提高代码的可读性和可维护性。

相关文章:

  • 利用optisystem软件仿真半导体激光器的P-I特性曲线
  • DeepSeek:中国大模型领域的“效率革命者”与开源先锋
  • C++ primier plus 函数探幽第二部分
  • 黑金风格人像静物户外旅拍Lr调色教程,手机滤镜PS+Lightroom预设下载!
  • Jmeter进行http接口测试详解
  • 网络编程-----服务器(多路复用IO 和 TCP并发模型)
  • 使用 AIStor、MLflow 和 KServe 将模型部署到 Kubernetes
  • 网络安全创刊 网络安全紫队
  • 第六课:数据存储三剑客:CSV/JSON/MySQL
  • Centos8部署mongodb报错记录
  • 从星链到数字样机:直升机智能化升级的双引擎
  • 代码随想录算法营Day59 | 寻找存在的路径, 冗余连接,冗余连接II
  • 使用eNSP进行路由策略与引入实验
  • Manus AI : Agent 元年开启.pdf
  • OpenHarmony子系统开发 - AI框架开发指导
  • 机器学习常见面试题
  • 第TR3周:Pytorch复现Transformer
  • 深入解析 JVM —— 从基础概念到实战调优的全链路学习指南
  • Permute for Mac v3.12.1 文件格式转换器 支持M、Intel芯片
  • 多模态知识图谱融合
  • 现在什么网站做外贸的最好/免费的html网站
  • 兰州做网站改版的公司/引流推广平台
  • 真人真做网站/广东全网推广
  • 网站设计心的/百度站长统计
  • 深圳宝安外贸网站建设公司/设计网站
  • 网站开发实习日记/百度问一问人工客服怎么联系