You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

编码挑战超时问题求解:管道与星号计数算法优化

编码练习优化问题:统计指定区间内成对管道间的星号数量

题目要求

输入为包含|和*的字符串(例如**|*|*|**|***),实现函数List<int> countItems(string line, List<int> startLocations, List<int> endLocations),统计位于成对|之间的*字符数量。其中startLocations和endLocations是字符串line中需考虑的起始和结束位置数组(1-based索引)。

示例:

  • 若line=*|*|*,startLocations=[1],endLocations=[3],需检查子串*|*,因仅有1个管道,结果为0;
  • 若范围是1到5,结果为1,因仅有1个*在两个管道之间。

遇到的问题

我写出的代码能通过约半数测试用例,但其余因超时(超过3秒)失败。推测需要仅遍历字符串一次的优化方案,想了解此类问题的解决思路、相关概念及同类编程练习资源。

我的代码

List<int> countItems(string line, List<int> startLocations, List<int> endLocations)
{
    var results = new List<int>();
    
    if (String.IsNullOrWhiteSpace(line) || startLocations.Count == 0)
    {
        return results;
    }

    for (var i = 0; i < startLocations.Count; i++)
    {
        var startIndex = startLocations[i] - 1;
        var endIndex = endLocations[i] - 1;

        var start = false;
        var total = 0;
        var tempTotal = 0;

        for (var j = startIndex; j < endIndex; j++)
        {
            if (!start && line[j] == '|')
            {
                start = true;
                tempTotal = 0;
            }
            else if (start && line[j] == '*')
            {
                tempTotal++;
            }
            else if (line[j] == '|')
            {
                total += tempTotal;
                tempTotal = 0;
            }
        }

        if (line[endIndex] == '|')
        {
            total += tempTotal;
        }

        results.Add(total);
    }

    return results;
}

优化思路与解决方案

核心问题分析

原代码的时间复杂度为O(Q*N)(Q为查询次数,N为字符串长度),当Q和N都较大时(如均为105级别),总操作量会达到1010,必然触发超时。需要将时间复杂度优化到O(N + Q*logN),核心思路是预处理静态数据+二分查找快速查询。

预处理关键数据

只需要遍历字符串一次,生成三个核心数组:

  1. pipePositions:存储所有|在字符串中的0-based索引,后续用于快速定位查询区间内的管道。
  2. totalStars:前缀和数组,totalStars[i]表示字符串前i个字符(0到i-1)中*的总数,用于快速计算任意区间内的*数量。
  3. pairPrefix:前缀和数组,pairPrefix[k]表示前k对相邻管道之间的*总数(即pipePositions[0]-pipePositions[1]到pipePositions[k-1]-pipePositions[k]的*总和)。

优化后的代码实现

List<int> countItems(string line, List<int> startLocations, List<int> endLocations)
{
    var results = new List<int>();
    if (string.IsNullOrWhiteSpace(line) || startLocations.Count == 0)
        return results;

    // 预处理1:收集所有管道的位置
    List<int> pipePositions = new List<int>();
    for (int i = 0; i < line.Length; i++)
    {
        if (line[i] == '|')
            pipePositions.Add(i);
    }

    // 预处理2:*的前缀和数组
    List<int> totalStars = new List<int>(line.Length + 1);
    totalStars.Add(0);
    int starCount = 0;
    for (int i = 0; i < line.Length; i++)
    {
        if (line[i] == '*')
            starCount++;
        totalStars.Add(starCount);
    }

    // 预处理3:成对管道间*的前缀和数组
    List<int> pairPrefix = new List<int>();
    pairPrefix.Add(0);
    for (int k = 0; k < pipePositions.Count - 1; k++)
    {
        int leftPipe = pipePositions[k];
        int rightPipe = pipePositions[k + 1];
        // 计算当前管道对之间的*数量
        int starsBetween = totalStars[rightPipe] - totalStars[leftPipe + 1];
        pairPrefix.Add(pairPrefix.Last() + starsBetween);
    }

    // 处理每个查询
    for (int i = 0; i < startLocations.Count; i++)
    {
        int start = startLocations[i] - 1;
        int end = endLocations[i] - 1;

        // 找到第一个 >= start 的管道索引
        int leftPipeIdx = pipePositions.BinarySearch(start);
        if (leftPipeIdx < 0)
            leftPipeIdx = ~leftPipeIdx;

        // 找到最后一个 <= end 的管道索引
        int rightPipeIdx = pipePositions.BinarySearch(end);
        if (rightPipeIdx < 0)
            rightPipeIdx = ~rightPipeIdx - 1;

        // 没有成对管道的情况
        if (rightPipeIdx <= leftPipeIdx)
        {
            results.Add(0);
            continue;
        }

        // 计算有效成对管道间的*总数
        results.Add(pairPrefix[rightPipeIdx] - pairPrefix[leftPipeIdx]);
    }

    return results;
}

相关概念

  • 前缀和数组:将区间查询的计算从O(N)压缩到O(1)的经典技巧,通过提前累加数据避免重复遍历。
  • 二分查找:在有序数组中快速定位目标元素,时间复杂度O(logM)(M为管道数量),用于快速锁定查询区间内的首尾有效管道。
  • 离线预处理:先一次性处理静态的字符串数据,再批量响应所有查询,彻底避免重复计算带来的性能损耗。

同类编程练习资源

  • 重点练习区间查询、前缀和相关题目,比如:
    • 给定数组,多次查询区间内偶数/奇数的个数
    • 统计字符串中多次查询区间内的元音字母数量
    • 二维前缀和相关的矩阵区间求和/计数问题

内容的提问来源于stack exchange,提问作者Quintonn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 09:36:26