首页/新闻资讯/正文详情

环形字符串子串权值求和的动态规划与滑动窗口解法

发布时间:2026/9/23 6:32:15 来源:云帆数科 栏目:资讯中心
环形字符串子串权值求和的动态规划与滑动窗口解法
1. 题目解析与思路拆解这道题目考察的是环形字符串中子串权值求和的问题属于动态规划与滑动窗口结合的高级应用。我们先来拆解题目要求给定一个由0和1组成的环形字符串需要计算所有长度≥2的子串中01子序列的数量之和。这里的01子序列指的是在原字符串中删除任意字符后剩下的恰好是01的序列。1.1 关键概念理解环形字符串处理由于字符串是环形的常规的线性处理方法不再适用。常见的处理技巧是将原字符串复制一份接在自己后面这样就能用线性方法模拟环形特性。子序列与子串的区别子串必须连续选取的字符序列子序列可以不连续选取的字符序列权值计算每个子串的权值是其包含01子序列的数量。例如001有2个01子序列删除第二个0和删除第一个0。1.2 暴力解法分析最直观的解法是枚举所有长度≥2的子串对每个子串统计其中01子序列的数量。对于长度为n的字符串子串数量O(n²)每个子串统计01子序列O(m²)m为子串长度 总时间复杂度为O(n⁴)对于n1e5显然不可行。1.3 优化思路我们需要找到一种能在线性时间内计算所有子串权值之和的方法。观察发现每个01子序列的贡献可以拆解为对于每个1它前面有多少个0在环形情况下滑动窗口可以高效维护0和1的数量关系因此我们可以采用滑动窗口前缀和的方法将时间复杂度优化到O(n)。2. 算法设计与实现细节2.1 滑动窗口设计为了处理环形字符串我们将原字符串s复制一份得到ss这样任何环形子串都可以表示为这个扩展字符串中的一个线性子串。定义滑动窗口大小为n原字符串长度窗口从左向右滑动每次移动一个位置。我们需要维护以下变量num0窗口内0的数量sum0窗口内所有0的位置和相对于窗口起始位置num1窗口内1的数量sum辅助变量记录当前窗口内所有0对后续1的贡献sum1当前窗口内01子序列的总数2.2 核心算法流程初始化窗口处理前n个字符统计初始的num0、sum0、num1、sum和sum1滑动窗口移除最左边字符的影响加入右边新字符的影响累加当前窗口的sum1到最终答案模运算处理由于结果可能很大每次累加后取模2.3 关键操作解释加入0时的处理if (s[i] 0) { num0; sum0 i; // 记录0的位置 }加入1时的处理else { // s[i] 1 num1; sum1 sum0; // 新1与前面所有0形成新子序列 sum num0; // 记录这些0对后续的贡献 }移除字符时的处理// 移除窗口左端点元素 i - n 的影响 sum1 - sum; // 去掉以移除元素为起点产生的贡献 sum0 - num0; // 更新所有0下标和 if (s[i - n] 0) { num0--; // 0数量减少 sum - num1; // 0被移除减少对后续1的贡献 } else { num1--; // 1数量减少 }3. 代码实现与注释以下是完整实现代码附详细注释#include iostream #include string using namespace std; #define rep(i, a, b) for (int i (a), _##i (b); i _##i; i) using ll long long; const int N 1e5 5; const int mod 1e9 7; // 全局变量 ll ans 0; // 最终答案 ll sum 0; // 当前窗口内0对后续1的贡献 ll num0 0; // 当前窗口内0的数量 ll sum0 0; // 当前窗口内所有0的下标之和 ll num1 0; // 当前窗口内1的数量 ll sum1 0; // 当前窗口内01子序列数量 void solve() { int n; cin n; string s; cin s; // 为了模拟环形把s复制一份自己接到自己后面并在前面加空格使下标从1开始 s s s; // 初始化滑动窗口处理前n个字符 rep(i, 1, n) { if (s[i] 0) { num0; sum0 i; // 记录0的位置 } else { // s[i] 1 num1; sum1 sum0; // 新1与前面所有0形成新子序列 sum num0; // 记录这些0对后续的贡献 } } // 滑动窗口处理后续n个字符 rep(i, n 1, 2 * n) { // 移除窗口左端点元素 i - n 的影响 sum1 - sum; // 去掉以移除元素为起点产生的贡献 sum0 - num0; // 更新所有0下标和 if (s[i - n] 0) { num0--; // 0数量减少 sum - num1; // 0被移除减少对后续1的贡献 } else { num1--; // 1数量减少 } // 加入新的元素 s[i] if (s[i] 0) { num0; sum0 i; // 加入0记录位置 } else { // s[i] 1 num1; sum1 sum0; // 新加入的1与已有0形成新子序列 sum num0; // 0的数量影响sum } // 累加当前窗口的贡献 ans (ans sum1) % mod; } cout ans \n; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int t 1; // cin t; // 如果有多组测试数据可以打开 while (t--) { solve(); } return 0; }4. 算法复杂度分析时间复杂度O(n)初始化窗口O(n)滑动窗口处理O(n)每个字符最多被处理两次加入和移除空间复杂度O(n)主要空间消耗来自字符串的扩展存储5. 常见问题与调试技巧5.1 边界情况处理全0或全1字符串权值总和应为0需要确保算法在这种情况下能正确输出0最小长度n2只有1个子串即整个字符串需要单独验证这种情况模运算处理确保每次累加后都取模特别注意减法操作后可能出现负数需要加mod再取模5.2 调试技巧小规模测试先用手算验证小例子如n3的001确保窗口滑动时各变量的更新逻辑正确变量跟踪打印窗口滑动过程中各变量的值特别关注sum1的增减是否符合预期环形特性验证构造一个明显需要环形处理的案例如011验证算法是否能正确处理跨越首尾的子串5.3 性能优化输入输出加速ios::sync_with_stdio(false); cin.tie(nullptr);这可以显著提高C的I/O速度对于大规模输入很重要。变量复用复用全局变量减少内存分配但要注意每次solve()前是否需要重置全局变量避免不必要计算在滑动窗口时只更新受影响的变量例如移除1时不会影响sum变量6. 算法扩展与变种6.1 类似问题线性字符串版本去掉环形处理问题会更简单可以用类似的双指针/滑动窗口方法统计10子序列逻辑类似但需要反向处理记录每个1后面有多少个0多字符统计如统计001、110等更复杂的子序列需要维护更多状态变量6.2 其他解法思路前缀和优化预处理0和1的前缀数量可以快速计算任意区间内的01子序列数分治法将环形字符串拆分为线性段处理合并时需要特殊处理跨越分割点的子串动态规划定义dp[i][j]表示处理到第i个字符时的某种状态适用于更复杂的子序列统计问题在实际编码竞赛中滑动窗口方法通常是这类问题的最优解因为它既高效又易于实现。理解并掌握这种方法的思维模式可以解决许多类似的子串统计问题。

相关推荐

告别版本升级API崩溃:兔子换源码速查手册与进阶避坑指南
告别版本升级API崩溃:兔子换源码速查手册与进阶避坑指南

告别版本升级API崩溃:兔子换源码速查手册与进阶避坑指南 版本升级后 API 全变了?别慌,这份【兔子换】源码速查手册带你从底层逻辑彻底搞懂它。很多开发者在接手旧项目或升级依赖时,最头疼的就是接口突然失效,导致线上事故频发。我们不再依赖零散… · 2026/9/23 6:32:15

BigemapPro球体海图投影功能解析与应用
BigemapPro球体海图投影功能解析与应用

1. 项目概述BigemapPro专题制图工具最新推出的球体海图投影功能,彻底改变了传统海洋专题图制作的繁琐流程。作为一名长期从事海洋地理信息系统开发的工程师,我亲测这个"一键投影"功能后,必须说这可能是近五年来海洋制图领域最实用的… · 2026/9/23 6:32:15

开源视频剪辑替代指南:从剪映迁移到Shotcut/Kdenlive与FFmpeg实战
开源视频剪辑替代指南:从剪映迁移到Shotcut/Kdenlive与FFmpeg实战

剪映的会员体系铺开之后,评论区天天有人问“有没有免费又能打的替代”。说实话,剪辑工具这事儿,一旦开始按月付费,很多人的第一反应不是掏钱,而是找退路。GitHub 上不少开源剪辑项目的星标数在最近一段时间涨得飞快&am… · 2026/9/23 6:32:09

DTS DM到DM
DTS DM到DM

概述 进行数据迁移 迁移准备 1.停止应用 2.确认要迁移的用户(模式、数据库) 3.记录原数据库中要迁移的对象的数量 4.记录原数据库中要迁移的所有对象名称 5.记录原数据库中要迁移的表的数据量 6.创建目标数据及实例 7.创建目标数据的表空间及用户 迁移管… · 2026/9/23 7:19:38

AI Agent安全审计Skill实战:从手动扫描到自动化技能包
AI Agent安全审计Skill实战:从手动扫描到自动化技能包

前阵子给团队做安全自查,我顺手把几个老项目扔给AI编程助手,结果发现一件挺有意思的事:AI能找出不少代码里的坑,但每次都要我在对话框里反复交代项目背景、扫描范围、重点方向,甚至还得提醒它别看第三方依赖目录……同… · 2026/9/23 7:19:38

金融系统架构设计实战:账务模型、幂等与分布式一致性
金融系统架构设计实战:账务模型、幂等与分布式一致性

金融服务系统,本质上就是一个处理资金流转、账户管理、交易记录与合规风控的复杂业务综合体。如果你刚接手这类项目,或者正打算从零搭建一套金融级别的后端服务,这篇内容就是给你准备的。我不会讲那些教科书上都能查到的概念,直接… · 2026/9/23 7:19:38

STM32燃气监测系统:三级报警与高精度ADC实战设计
STM32燃气监测系统:三级报警与高精度ADC实战设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/23 7:19:38

AI内容同质化现象解析与解决方案
AI内容同质化现象解析与解决方案

1. 现象观察:AI修改AI内容的循环怪圈最近两年有个特别有趣的现象:当人们用AI工具修改AI生成的内容时,结果往往会变得更"AI化"。我做过一个实验,把一段GPT-3.5生成的文案分别用五个不同的AI改写工具处理,结果… · 2026/9/23 7:19:38

3步搞定五级分类标准,版本升级API全变?一文搞懂
3步搞定五级分类标准,版本升级API全变?一文搞懂

3步搞定五级分类标准,版本升级API全变?一文搞懂 版本升级后 API 全变了,五级分类标准 数据对不上,这是很多市政公用工程从业者最近最头疼的问题。别急,今天不扯虚的,直接给你一套经过实战检验的优化方案。我们要解决的问题很具体:在工程管理… · 2026/9/23 7:19:32

3招搞定手机怎么下载微信面试难题实战项目解析
3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧
Win7无线热点配置工具源码解析:解决API失效的3个实战技巧

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧 Win7无线热点配置工具在Win10/11上跑不动?不是你的问题,是版本升级后 API 全变了。很多老项目里的 netsh wlan… · 2026/9/23 0:00:36

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码