2055. 蜡烛之间的盘子

💡LeetCode题解:统计两根蜡烛之间的盘子数量(Plates Between Candles)


🧩题目描述.

在一张长桌子上,盘子 (*) 和 蜡烛 (|) 排成一列,形成一个字符串 s,每个字符代表一个物体:

  • * 表示盘子
  • | 表示蜡烛

同时,给出一个二维整数数组 queries,其中 queries[i] = [left_i, right_i] 表示我们需要统计字符串 s[left_i...right_i] 这个子串中两根蜡烛之间的盘子数

注意:一个盘子只在其左边和右边都至少存在一根蜡烛时,才算是处于蜡烛之间。


示例 1:

输入:
s = "**|**|***|"
queries = [[2,5],[5,9]]

输出:
[2,3]

解释:
- queries[0] 对应的子串为 "|**|",有 2 个盘子夹在两根蜡烛中间。
- queries[1] 对应的子串为 "|***|",有 3 个盘子夹在蜡烛之间。

示例 2:

输入:
s = "***|**|*****|**||**|*"
queries = [[1,17],[4,5],[14,17],[5,11],[15,16]]

输出:
[9,0,0,0,0]

解释:
- queries[0] 涉及的子串有多个蜡烛与盘子,最终有 9 个盘子被夹在蜡烛之间。
- 其余的查询要么没有成对的蜡烛,要么中间没有盘子。

🧠解题分析

这个问题的关键在于高效地处理多个查询。暴力解法(每次查询都遍历子串统计)会超时,因此需要使用预处理 + 前缀和 + 双向扫描的方法优化。


✅我们需要解决两个问题:

  1. 快速确定每次查询中的有效蜡烛范围
    • 即区间中最靠左的一根蜡烛 left 和最靠右的一根蜡烛 right,满足 left < right
  2. 快速统计两根蜡烛之间的盘子数量
    • 使用前缀和数组即可做到这一点。

🚀解题方法

步骤一:预处理

  1. **盘子前缀和 ****prefix_sum**
    prefix_sum[i] 表示从开头到位置 i-1(即 s[0:i-1])中的盘子数。
  2. 最近蜡烛索引
    • left_candle[i] 表示 i 左侧最近的蜡烛(含自身)
    • right_candle[i] 表示 i 右侧最近的蜡烛(含自身)

步骤二:处理查询

对于每个 [left, right]

  1. 找到 left 右侧最近的蜡烛 l = right_candle[left]
  2. 找到 right 左侧最近的蜡烛 r = left_candle[right]
  3. 如果 l < r,说明存在合法区间,结果为 prefix_sum[r] - prefix_sum[l]
  4. 否则返回 0

🧪代码实现(Python)

from typing import List

class Solution:
    def platesBetweenCandles(self, s: str, queries: List[List[int]]) -> List[int]:
        n = len(s)
        prefix_sum = [0] * (n + 1)
        left_candle = [-1] * n
        right_candle = [-1] * n

        # 1. 构造前缀和:统计盘子数量
        for i in range(n):
            prefix_sum[i + 1] = prefix_sum[i] + (1 if s[i] == '*' else 0)

        # 2. 从左往右找每个位置的左侧最近蜡烛
        prev = -1
        for i in range(n):
            if s[i] == '|':
                prev = i
            left_candle[i] = prev

        # 3. 从右往左找每个位置的右侧最近蜡烛
        next = -1
        for i in range(n - 1, -1, -1):
            if s[i] == '|':
                next = i
            right_candle[i] = next

        # 4. 处理查询
        result = []
        for left, right in queries:
            l = right_candle[left]
            r = left_candle[right]
            if l != -1 and r != -1 and l < r:
                result.append(prefix_sum[r] - prefix_sum[l])
            else:
                result.append(0)
        return result

📈时间与空间复杂度分析

操作复杂度
预处理前缀和O(n)
构造左右蜡烛索引O(n)
每个查询处理O(1)
总体时间复杂度O(n + q),其中 n
是字符串长度,q
是查询数
空间复杂度O(n)

✅ 相比暴力解法(O(qn)),大大提升了效率,能够处理超大数据量。


🆚算法对比

方法思路查询复杂度是否能通过大数据集
暴力遍历每次从 left 到 right 查找蜡烛并统计O(n)❌ 超时
前缀和 + 辅助数组预处理蜡烛位置和盘子数O(1)✅ 高效通过

🔍示例验证

s = "**|**|***|"
queries = [[2,5],[5,9]]
# 输出: [2,3]

s = "***|**|*****|**||**|*"
queries = [[1,17],[4,5],[14,17],[5,11],[15,16]]
# 输出: [9,0,0,0,0]

运行结果完全符合预期!


📝总结

本题是前缀和与双指针结合的典型应用场景,在处理需要快速区间查询的问题时非常有用。其核心思想在于通过预处理,把多次查询的复杂度从线性降到常数。

适合考察:

  • 前缀和构建
  • 双向扫描
  • 数组索引缓存
  • 边界处理技巧
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值