力扣2222题终极攻略:前缀和与后缀和在字符串模式统计中的惊艳应用 | 算法新手必看
一、问题理解与算法思路
题目要求统计二进制字符串中"010"或"101"模式的出现次数。核心思路是通过预处理前缀和后缀数组,避免暴力枚举带来的高时间复杂度。
关键算法步骤:
预处理前缀0和1的数量
预处理后缀0和1的数量
遍历中间位置计算有效组合数
二、完整代码实现(带详细注释)
class Solution { public: long long numberOfWays(string s) { int n = s.size(); // 定义前缀数组和后缀数组 vector prefix0(n, 0), prefix1(n, 0); vector suffix0(n, 0), suffix1(n, 0); // 计算前缀0和1的数量 prefix0[0] = (s[0] == '0'); // 初始化第一个字符 prefix1[0] = (s[0] == '1'); for (int i = 1; i < n; ++i) { prefix0[i] = prefix0[i-1] + (s[i] == '0'); // 累加0的个数 prefix1[i] = prefix1[i-1] + (s[i] == '1'); // 累加1的个数 } // 计算后缀0和1的数量 suffix0[n-1] = (s[n-1] == '0'); // 初始化最后一个字符 suffix1[n-1] = (s[n-1] == '1'); for (int i = n-2; i >= 0; --i) { suffix0[i] = suffix0[i+1] + (s[i] == '0'); // 反向累加0的个数 suffix1[i] = suffix1[i+1] + (s[i] == '1'); // 反向累加1的个数 } long long res = 0; // 遍历每个中间位置 for (int i = 1; i < n-1; ++i) { if (s[i] == '0') { // 计算101模式:左边1的数量 × 右边1的数量 res += (long long)prefix1[i-1] * suffix1[i+1]; } else { // 计算010模式:左边0的数量 × 右边0的数量 res += (long long)prefix0[i-1] * suffix0[i+1]; } } return res; } };
三、算法核心解析
前缀数组:记录到当前位置为止0和1的累计数量
后缀数组:记录从当前位置到末尾0和1的累计数量
组合计算:利用前缀后缀数组快速计算可能组合数
四、复杂度分析与优化
时间复杂度:O(n),只需三次线性遍历
空间复杂度:O(n),使用四个辅助数组
优化建议:可进一步优化为使用单个变量代替后缀数组
五、常见问题解答
Q:为什么需要同时计算前缀和后缀? A:前缀帮助我们快速获取左侧信息,后缀帮助我们快速获取右侧信息。
Q:如何处理特殊边界情况? A:代码已自动处理边界,如首尾字符不会作为中间位置。
Q:算法是否可以处理更长模式? A:当前算法针对3字符模式,更长模式需要调整算法结构。
原创内容 转载请注明出处