好的,阿杰。我们一起来详细分析题目 2086. 喂食仓鼠的最小食物桶数(LeetCode题号 2086):“喂食仓鼠的最小食物桶数”,然后给出 C++ 的贪心解法。你可以根据这个思路改写文案或整理成速查卡片。


题目描述

给定一个字符串 hamsters,长度 n。

  • hamsters[i] == 'H' 表示下标 i 处有一只仓鼠。
  • hamsters[i] == '.' 表示下标 i 处是空格。
    你需要放置“食物桶”(bucket)在某些空格(即 '.' 位置),使得每只仓鼠至少能从左或右 相邻位置 拿到一个食物桶。一个桶只能服务它两侧各最多一只仓鼠(按题意是:桶放在 i 的话可喂 i-1 或 i+1 如果有仓鼠)。
    要求返回放桶的最小数量;如果无法喂所有仓鼠返回 -1。

贪心思路分析

这是一个字符串 + 贪心的问题。关键在于:尽量将桶“共享”给左右两侧的仓鼠,从而减少桶的数量。我们推荐从左往右遍历字符串,遇到仓鼠时优先考虑将桶放 右侧空位,因为这样后面的仓鼠可能也能受益。具体思路:

  1. 初始化计数 res = 0
  2. 遍历 i = 0 .. n-1
    • 如果 hamsters[i] == 'H':这只仓鼠还没被喂。
      • 首先看右侧:如果 i+1 < n && hamsters[i+1] == '.',那么我们在 i+1 放一个桶。这样这个桶可以喂当前仓鼠(i)和可能 i+2 的仓鼠(如果 i+2 是‘I’)。于是 res++,然后我们 跳过 i+2(即令 i += 2) 因为我们已在 i+1 放了桶,i+2若为仓鼠可以共用这个桶。
      • 否则,看左侧:如果 i-1 >= 0 && hamsters[i-1] == '.',则在 i-1 放一个桶,res++
      • 否则:无法为仓鼠 i 放置桶 => 返回 -1。
  3. 遍历结束后返回 res

这种策略的直觉:优先在右侧放桶,是因为我们在当前位置的仓鼠右侧空位如果可用,就把桶放在那里,从而可能同时服务自己和下一个仓鼠,减少桶数。若右侧不可,则考虑左侧备用位置。若都不可,则失败。

参考文章里也正是这样描述。 (CSDN博客)
你也可以查看另一篇解答。 (力扣 LeetCode)


C++ 代码模板

下面是一个标准的 C++ 实现(你可以根据自己的风格改写为速查卡片):

class Solution {
public:
    int minimumBuckets(string hamsters) {
        int n = hamsters.size();
        int res = 0;
        for (int i = 0; i &lt; n; i++) {
            if (hamsters[i] == 'H') {
                // 尝试右侧放桶
                if (i + 1 &lt; n &amp;&amp; hamsters[i+1] == '.') {
                    res++;
                    i += 2;           // 跳过 i+1 放桶后,i+2 可跳
                }
                else if (i - 1 >= 0 &amp;&amp; hamsters[i-1] == '.') {
                    // 右侧无法,则考虑左侧放桶
                    res++;
                }
                else {
                    // 无法放桶
                    return -1;
                }
            }
        }
        return res;
    }
};

几点说明:

  • i += 2; 的使用:当我们在 i+1 放桶之后,我们知道仓鼠 i 被喂了,同时 i+1 是桶位置,不是仓鼠位置,所以下一可能未被喂的仓鼠最早在 i+2。跳过 i+1i+2(i+2 实际会在下一循环 i++ 到 i+2)可以避免重复检查。
  • 在放桶之后,不修改字符串,而是只通过控制 i 跳跃来保证不会为已经处理的仓鼠重复计数。
  • 此方法从左向右一次遍历,时间复杂度 O(n),空间 O(1)。

复杂度分析

  • 时间复杂度:O(n),n=字符串长度。
  • 空间复杂度:O(1),除输入外只用了常量额外空间。
  • 正确性:贪心选择“遇 H 优先右侧桶”是安全的,因为右侧桶能够覆盖当前位置的仓鼠且最大化覆盖范围(未来可能覆盖下一只仓鼠),从而实现最少桶。若右侧不可用,再考虑左侧,否则失败。

注意事项 & 边界情况

  • 当字符串长度为 0 或无仓鼠时,返回 0。
  • 当字符串某处为 'H' 且左右都不是 '.'(例如边界 'H''H' 相邻或者无空点),就返回 -1。
    例: "HH""H"(当只有一个 H 且左右无 ‘.’) => -1。
  • 一定注意跳跃逻辑:在右侧放桶后跳过适当位置,防止重复计数或错误位置。
  • 当在左侧放桶时,不跳跃,因为左侧桶放在 i-1,但 i+1 可能仍是仓鼠未被喂,需要在下一个循环继续检查。