跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
C++算法

C++ 算法实战:数字变换、矩阵优化与前缀和技巧

C++ 算法实战涵盖三道经典题目:数字位变换利用字符 ASCII 特性简化判断;二维数组求和通过行列预存和将复杂度降至 O(NM);区间最值问题对比滑动窗口与前缀和两种解法,重点讲解如何优化重复计算及边界处理。内容聚焦核心逻辑与代码规范,适合笔试面试复习。

二进制发布于 2026/3/15更新于 2026/4/275 浏览
C++ 算法实战:数字变换、矩阵优化与前缀和技巧

一、数字变换

给定一个整数,我们需要修改它的每一位:如果某一位是奇数,就变成 1;如果是偶数,就变成 0。最后输出处理后的结果。

思路解析

这道题的核心在于模拟过程。虽然可以直接对数字取模操作,但将其视为字符串处理会更直观。

遍历字符串中的每个字符,判断其奇偶性并替换即可。这里有个小技巧:字符 '0' 到 '9' 的 ASCII 码中,数字 0 到 9 的奇偶性与数值本身的奇偶性是一致的(例如 '0' 是 48 为偶数,'1' 是 49 为奇数),因此直接对字符进行 %2 判断即可,无需减去 '0'。

最后得到的字符串可能包含前导零,使用 stoi 函数可以方便地将其转换为整数并自动去除前导零。

代码实现

#include <iostream>
#include <string>

using namespace std;

int main() {
    string str;
    cin >> str;
    
    for (int i = 0; i < str.size(); i++) {
        if (str[i] % 2 == 0) {
            str[i] = '0';
        } else {
            str[i] = '1';
        }
    }
    
    cout << stoi(str) << endl;
    return 0;
}

二、二维数组求和优化

输入一个 $n \times m$ 的二维数组,计算每个位置 $(i, j)$ 的得分。得分规则为该位置所在行的所有元素之和加上所在列的所有元素之和。

思路解析

最直接的暴力解法是对于每个点都重新遍历行和列求和,时间复杂度会达到 $O(n \cdot m \cdot (n + m))$,在数据量较大时容易超时。

观察发现,计算 $(i, j)$ 和 $(i, j+1)$ 时,第 $i$ 行的总和是不变的。我们可以预先计算出每一行和每一列的总和,存储起来。

这样,任意位置 $(i, j)$ 的得分就可以通过公式快速得出:row_sum[i] + col_sum[j] - arr[i][j]。注意这里减去了 arr[i][j],因为它在行和与列和中被重复计算了一次。

代码实现

#include <iostream>

using namespace std;

  N =  + ;
  row[N];
  col[N];

{
     n, m;
    (, &n, &m);
    
    
      **arr =   *[n];
    ( i=; i<n; ++i) arr[i] =   [m];

     ( i = ; i < n; i++) {
         ( j = ; j < m; j++) {
            (, &arr[i][j]);
            row[i] += arr[i][j];
            col[j] += arr[i][j];
        }
    }

     ( i = ; i < n; i++) {
         ( j = ; j < m; j++) {
            (, row[i] + col[j] - arr[i][j]);
        }
        ();
    }

    ( i=; i<n; ++i) [] arr[i];
    [] arr;
     ;
}
const
int
1e6
10
long
long
long
long
int main()
int
scanf
"%d %d"
// 动态分配或使用 vector 更安全,此处保持原逻辑结构
long
long
new
long
long
for
int
0
new
long
long
for
int
0
for
int
0
scanf
"%lld"
for
int
0
for
int
0
printf
"%lld "
printf
"\n"
for
int
0
delete
delete
return
0

三、滑动窗口与前缀和

小红吃桃子,每天获得快乐值 $a_i$ 和羞耻值 $b_i$,效果持续 $k$ 天。要求找到开始吃桃子的日期,使得这 $k$ 天的总快乐值最大;若快乐值相同,则选择羞耻值最小的那一天。

思路解析

方法一:滑动窗口

这是一个典型的定长窗口问题。我们维护一个长度为 $k$ 的窗口,记录当前窗口内的快乐值和与羞耻值和。

当窗口向右移动时,只需减去离开窗口的元素,加上新进入窗口的元素。同时维护全局的最大快乐值 hMax 和对应的最小羞耻值 sMin。当遇到新的最大值或相同最大值下更小的羞耻值时,更新答案。

方法二:前缀和

既然需要频繁查询区间和,前缀和是另一个高效的选择。

预处理两个前缀和数组,分别存储快乐值和羞耻值的累积和。对于起始位置 $i$,区间和可以通过 prefix[i+k-1] - prefix[i-1] 在 $O(1)$ 时间内获取。这种方法同样避免了重复计算,且代码逻辑通常比滑动窗口更简洁。

注意边界情况,从 $i$ 开始必须有足够的天数,即 $i$ 的范围是 $[1, n-k+1]$。

代码实现:滑动窗口

#include <iostream>

using namespace std;

const int N = 1e5 + 10;
long long h[N], s[N];

int main() {
    int n, k;
    cin >> n >> k;
    
    for (int i = 1; i <= n; i++) cin >> h[i];
    for (int i = 1; i <= n; i++) cin >> s[i];
    
    int left = 1, right = 1;
    long long hSum = 0, sSum = 0;
    long long hMax = 0, sMin = 0;
    int ret = 0;
    
    while (right <= n) {
        hSum += h[right];
        sSum += s[right];
        
        while (right - left + 1 > k) {
            hSum -= h[left];
            sSum -= s[left];
            left++;
        }
        
        if (right - left + 1 == k) {
            if ((hSum > hMax) || (hSum == hMax && sSum < sMin)) {
                ret = left;
                hMax = hSum;
                sMin = sSum;
            }
        }
        right++;
    }
    
    cout << ret << endl;
    return 0;
}

代码实现:前缀和

#include <iostream>

using namespace std;

const int N = 1e5 + 10;
long long h[N], s[N];
long long hSum[N], sSum[N];

int main() {
    int n, k;
    cin >> n >> k;
    
    for (int i = 1; i <= n; i++) {
        cin >> h[i];
        hSum[i] = hSum[i - 1] + h[i];
    }
    
    for (int i = 1; i <= n; i++) {
        cin >> s[i];
        sSum[i] = sSum[i - 1] + s[i];
    }
    
    int ret = 0;
    long long hMax = 0, sMin = 0;
    
    for (int i = 1; i <= n - k + 1; i++) {
        long long numh = hSum[i + k - 1] - hSum[i - 1];
        long long nums = sSum[i + k - 1] - sSum[i - 1];
        
        if ((numh > hMax) || (numh == hMax && nums < sMin)) {
            ret = i;
            hMax = numh;
            sMin = nums;
        }
    }
    
    cout << ret << endl;
    return 0;
}

以上就是本次刷题的三道典型题目,涵盖了字符串处理、二维数组优化以及经典的滑动窗口与前缀和技巧。希望这些解析能帮助你更好地理解算法背后的逻辑。

目录

  1. 一、数字变换
  2. 思路解析
  3. 代码实现
  4. 二、二维数组求和优化
  5. 思路解析
  6. 代码实现
  7. 三、滑动窗口与前缀和
  8. 思路解析
  9. 方法一:滑动窗口
  10. 方法二:前缀和
  11. 代码实现:滑动窗口
  12. 代码实现:前缀和
  • 💰 8折买阿里云服务器限时8折了解详情
  • 💰 8折买阿里云服务器限时8折购买
  • 🦞 5分钟部署阿里云小龙虾了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Claude Code 安装配置与实战教程
  • 基于 Qwen3-VL 的自然语言驱动智能测试
  • Linux Shell 脚本中的 for 循环语句详解
  • Python 爬虫实战:抓取小说并保存为本地 TXT 文件
  • 如何在 Conda 中修改 Python 版本:安全迁移指南
  • DeepSeek-R1 使用技巧:如何平衡深度思考与回复质量
  • Node.js + Vue 电影推荐系统设计与实现
  • IROS 2025 精选论文盘点:从通用机器人到真实世界部署
  • Windows 系统下 MySQL 定时备份的三种实现方案
  • ThinkPHP 与 Laravel 框架的 Web 在线考试答题游戏设计与实现
  • 从多库并存到一库多能:金仓 KingbaseES 融合架构实践
  • Vite 自动导入与组件命名配置实战
  • 人工智能应用工程师(高级)核心技能体系与实战路径
  • Cesium Shader 材质体系解析:从 Fabric 到渲染管线
  • C++ 哈希表封装:模拟实现 unordered_map 与 unordered_set
  • C++ 搜索引擎核心:基于正倒排索引的 Searcher 实现解析
  • WSL2 部署 OpenClaw AI 助手:安装配置与实战运行
  • 数据结构:顺序表与链表经典算法实战
  • LeetCode 61. 旋转链表
  • 结合 cpolar 内网穿透远程部署 Open-Lovable 网页克隆工具

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online