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

心痛之窗:滑动窗口算法解爱与愁的心痛(洛谷P1614)

题目背景与情感共鸣

这道名为"爱与愁的心痛"的题目,巧妙地将情感主题与算法问题相结合。题目背景引用了《爱与愁的故事》和《我为歌狂》中的情节,营造出一种青春伤感的情感氛围。而算法核心则是寻找连续子数组的最小和,这种"心痛"的量化表达让人印象深刻。

问题分析

题目要求

给定一个包含n个正整数的序列(刺痛值),要求找出连续m个数字和的最小值

输入输出示例

输入:
8 3
1
4
7
3
1
2
4
3输出:
6

解释:连续3个刺痛值的最小和是1+2+3=6(对应第5、6、7个数字)

解题思路详解

核心算法:滑动窗口(Sliding Window)

滑动窗口算法是解决这类连续子数组问题的经典方法。其核心思想是维护一个固定大小的窗口,在数组上滑动,避免重复计算。

算法步骤

  1. 初始化窗口:计算前m个数字的和作为初始窗口和
  2. 滑动窗口:每次向右移动一位,减去离开窗口的数字,加上新进入窗口的数字
  3. 更新最小值:在滑动过程中记录遇到的最小和
  4. 边界处理:处理m=0的特殊情况

C++代码实现

基础版本:清晰易懂

#include <iostream>
#include <vector>
#include <climits> // 用于INT_MAX
using namespace std;int main() {int n, m;cin >> n >> m;vector<int> pain(n);for (int i = 0; i < n; i++) {cin >> pain[i];}// 处理m=0的特殊情况if (m == 0) {cout << 0 << endl;return 0;}// 初始化第一个窗口的和int current_sum = 0;for (int i = 0; i < m; i++) {current_sum += pain[i];}int min_sum = current_sum;// 滑动窗口for (int i = m; i < n; i++) {current_sum = current_sum - pain[i - m] + pain[i];if (current_sum < min_sum) {min_sum = current_sum;}}cout << min_sum << endl;return 0;
}

优化版本:处理边界更完善

#include <iostream>
#include <vector>
#include <climits>
using namespace std;int main() {int n, m;cin >> n >> m;// 边界情况处理if (n == 0 || m == 0) {cout << 0 << endl;return 0;}vector<int> pain(n);for (int i = 0; i < n; i++) {cin >> pain[i];}// 如果m大于n,实际上只能取n个连续数字int window_size = min(m, n);int current_sum = 0;// 计算第一个窗口for (int i = 0; i < window_size; i++) {current_sum += pain[i];}int min_sum = current_sum;// 滑动窗口处理剩余部分for (int i = window_size; i < n; i++) {current_sum += pain[i] - pain[i - window_size];min_sum = min(min_sum, current_sum);}cout << min_sum << endl;return 0;
}

单次遍历版本:极致简洁

#include <iostream>
#include <vector>
#include <climits>
using namespace std;int main() {int n, m;cin >> n >> m;vector<int> pain(n);for (int i = 0; i < n; i++) {cin >> pain[i];}if (m == 0) {cout << 0 << endl;return 0;}int current_sum = 0, min_sum = INT_MAX;for (int i = 0; i < n; i++) {current_sum += pain[i];// 当窗口大小达到m时开始滑动if (i >= m - 1) {min_sum = min(min_sum, current_sum);current_sum -= pain[i - m + 1];}}cout << min_sum << endl;return 0;
}

关键知识点深度解析

1. 滑动窗口算法(⭐⭐⭐⭐⭐)

  • 核心思想:维护固定大小的窗口,避免重复计算
  • 时间复杂度:O(n),只需遍历数组一次
  • 空间复杂度:O(1),只使用常数个额外变量

2. 边界条件处理(⭐⭐⭐⭐)

  • m=0情况:连续0个数字的和为0
  • m>n情况:实际窗口大小应为min(m,n)
  • 数组为空:n=0时的特殊处理

3. 算法优化技巧(⭐⭐⭐)

  • 提前终止:如果当前和已经很大,可以提前判断
  • 最小值更新:使用min函数简化代码
  • 变量复用:重复使用current_sum变量

测试用例与验证

标准测试用例

// 测试用例1:题目样例
输入:8 31 4 7 3 1 2 4 3
输出:6// 测试用例2:边界情况
输入:5 01 2 3 4 5
输出:0// 测试用例3:全相同数字
输入:4 25 5 5 5
输出:10// 测试用例4:递增序列
输入:5 31 2 3 4 5
输出:6

性能测试

根据数据规模分析:

  • n ≤ 20:任何算法都能轻松处理
  • n ≤ 1000:滑动窗口算法优势明显
  • n ≤ 3000:滑动窗口仍然高效(3000次操作)

常见错误与解决方法

错误1:窗口大小处理不当

// 错误:未处理m>n的情况
for (int i = 0; i < m; i++) { // 如果m>n会越界current_sum += pain[i];
}

解决

int window_size = min(m, n);
for (int i = 0; i < window_size; i++) {current_sum += pain[i];
}

错误2:索引计算错误

// 错误:索引计算偏差
current_sum = current_sum - pain[i - m] + pain[i];
// 当i=m时,i-m=0,正确

错误3:最小值初始化错误

// 错误:初始化为0
int min_sum = 0; // 如果所有和都大于0,会得到错误结果// 正确:初始化为极大值
int min_sum = INT_MAX;

竞赛技巧总结

  1. 识别滑动窗口模式:当问题涉及连续子数组时考虑此算法
  2. 边界测试优先:先处理m=0, n=0等边界情况
  3. 代码简洁性:使用标准库函数简化代码(如min, max)
  4. 提前优化:根据数据范围选择合适算法

实际应用拓展

滑动窗口算法在以下场景有广泛应用:

1. 数据流处理

// 实时数据流中的滑动平均值
class MovingAverage {
private:queue<int> window;int size;double sum;
public:MovingAverage(int size) : size(size), sum(0.0) {}double next(int val) {if (window.size() == size) {sum -= window.front();window.pop();}window.push(val);sum += val;return sum / window.size();}
};

2. 字符串处理

// 最长无重复字符子串
int lengthOfLongestSubstring(string s) {vector<int> charIndex(256, -1);int maxLength = 0, left = 0;for (int right = 0; right < s.length(); right++) {if (charIndex[s[right]] >= left) {left = charIndex[s[right]] + 1;}charIndex[s[right]] = right;maxLength = max(maxLength, right - left + 1);}return maxLength;
}

总结与提升建议

通过这道"爱与愁的心痛",我们掌握了:

  1. 滑动窗口核心思想:固定窗口大小的连续子数组处理
  2. 算法优化技巧:从O(n²)暴力解法优化到O(n)高效算法
  3. 边界处理能力:处理各种极端输入情况

进一步提升建议

  • 练习滑动窗口的变种问题(如可变窗口大小)
  • 学习双指针技术的其他应用
  • 掌握更多子数组相关问题的解法

"算法如人生,有时候我们需要在连续的经历中寻找最小的'心痛',而滑动窗口教会我们高效地审视每一个片段。"

这道题目不仅考察了算法能力,更通过情感主题让编程变得生动有趣。滑动窗口作为一种基础而强大的算法思想,值得深入理解和掌握。

http://www.dtcms.com/a/462332.html

相关文章:

  • 鸿蒙HTTP请求老是发不出去?一文带你彻底排查所有坑!
  • c# 开发网站开发做市级网站需要什么
  • 购物网站建设的必要性电商设计年终总结
  • 元宵节html+css+js 5页
  • 基于单片机的温度烟雾与漏电综合火灾报警系统设计
  • NX565NX578美光SSD固态闪存NX579NX580
  • 永久解决ubuntu网络连接问题
  • Linux timeout 命令详解:精准控制程序运行时长,避免资源浪费
  • 免费php域名网站专业品牌网站设计公司
  • 选择海外代理IP的方法
  • C语言中整数与浮点数的内存存储详解
  • 旅游建设投资公司网站建设局的全称
  • 网站建设的公司哪家强前端开发工程师是什么专业
  • 手机上自己如何做网站做视频网站用什么语言
  • 【图像处理基石】GIS图像处理入门:4个核心算法与Python实现(附完整代码)
  • 青岛+网站建设wordpress制作百度地图xml
  • 建站多语言方案
  • 网站开发时间计划智慧旅游网站开发与设计
  • 生成与无监督学习 —— 奶茶店的 “新品研发与原料优化体系”
  • 网站开发第三方支付用什么工具建设网站
  • [xboard] 27kernel内核中的kconfig工作原理及完整示例
  • Arduino 与 Raspberry Pi 的区别
  • 仿门户网站多功能js相册画廊源码divi wordpress
  • 【2026计算机毕业设计】基于Jsp的物业报修管理系统
  • 手机域名做网站中国谁第一家软文发稿
  • 【Docker技术】docker-compose.yml与Dockerfile解析
  • C++兼容性规则
  • 数据中台与数据生态:组织与平台的双轮驱动
  • 建站行业如何快速成第一单上海it公司有哪些
  • linux kernel v6.18 PCIe新增sysfs节点显示serial number