餐厅出入最少人数问题:贪心算法

张三最近开了家餐厅。张三想了解某一时段至少有多少不同人出入餐厅。张三就雇佣了一个人,呆在餐厅门口,有人进入餐厅,他就在纸上记下+,有人出餐厅,他就在纸上记下-。

假设同一时间没有两个人同时进入或出餐厅;也假设最初的时候餐厅中有足够多的人。问,这段时间里,至少有多少人出入餐厅。(不同人出入的顺序是随意的,一个人可以反复出入。)

Input

第一行是一个正整数m,表示有m组测试数据。(m<=100)

每组测试数据是一个由字符'+'和'-'组成的字符串。字符一个接一个,之间没有其他的分隔符,字符串的长度<=200。

Output

对于每一组测试数据输出一行,最少数量的人。

1 分析

这是一道非常经典的贪心算法 入门题,核心是通过最大化人员复用来最小化总人数。从问题本质、核心思路、算法步骤和代码实现四个方面来分析

一、问题本质拆解

首先明确几个关键前提和目标:

  1. 每个+对应一个进入事件 ,每个-对应一个离开事件
  2. 同一时间只有一个人进出,事件顺序严格对应
  3. 一个人可以反复出入(进入→离开→进入→离开...)
  4. 最初餐厅里有足够多的人,可以作为离开事件的"备用人员"
  5. 目标:给所有事件分配人员,满足"离开前必须在餐厅内"的规则,求最少需要多少不同的人

二、核心贪心思想

要让人数最少,就要尽可能让同一个人多次出入,而不是每次都用新人。我们可以把人分为两类:

  • 在餐厅内的人 :可以用来处理离开事件-
  • 在餐厅外的人 :可以用来处理进入事件+

当遇到一个事件时,优先复用已经使用过的人,只有当没有可用的复用人员时,才需要新增一个人。

三、算法步骤(O(n)时间复杂度)

我们只需要维护三个简单的计数变量,不需要复杂的数据结构:

  1. inside:当前在餐厅内的可用人数(已经进入过餐厅,还没离开)
  2. outside:当前在餐厅外的可用人数(已经离开餐厅,可以再次进入)
  3. min_people:最少需要的总人数

具体执行流程

遍历输入字符串的每个字符:

  • 遇到'+'(进入事件)

    1. 如果outside > 0:有已经出入过的人在外面,可以复用。将outside减1,inside加1。
    2. 否则:没有可用的复用人员,需要新增一个人。将min_people加1,inside加1。
  • 遇到'-'(离开事件)

    1. 如果inside > 0:有已经出入过的人在里面,可以复用。将inside减1,outside加1。
    2. 否则:没有可用的复用人员,需要新增一个最初就在餐厅里的人。将min_people加1,outside加1。

四、典型例子验证

例子1:输入"±-+"

步骤 字符 inside outside min_people 说明
初始 - 0 0 0 初始化
1 '+' 1 0 1 外面没人,新增1人
2 '-' 0 1 1 里面有人,复用出去
3 '-' 0 2 2 里面没人,新增1个最初的人
4 '+' 1 1 2 外面有人,复用进来

最终结果:2人,正确。

例子2:输入"+±-"

步骤 字符 inside outside min_people 说明
初始 - 0 0 0 初始化
1 '+' 1 0 1 新增1人
2 '+' 2 0 2 新增1人
3 '-' 1 1 2 复用1人出去
4 '-' 0 2 2 复用1人出去

最终结果:2人,正确。

例子3:输入"-+"

步骤 字符 inside outside min_people 说明
初始 - 0 0 0 初始化
1 '-' 0 1 1 里面没人,新增1个最初的人
2 '+' 1 0 1 外面有人,复用进来

最终结果:1人,正确。

五、代码实现C++

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

// 计算最少需要的人数
int calculateMinPeople(const string& s) {
    int inside = 0;    // 当前在餐厅内的可用人数(可离开)
    int outside = 0;   // 当前在餐厅外的可用人数(可进入)
    int minPeople = 0; // 最少总人数

    for (char c : s) {
        if (c == '+') { // 进入事件
            if (outside > 0) {
                // 优先复用已经出入过餐厅的人
                outside--;
                inside++;
            } else {
                // 没有可用的复用人员,新增一个人
                minPeople++;
                inside++;
            }
        } else { // 离开事件(c == '-')
            if (inside > 0) {
                // 优先复用已经在餐厅内的人
                inside--;
                outside++;
            } else {
                // 没有可用的复用人员,新增一个最初就在餐厅里的人
                minPeople++;
                outside++;
            }
        }
    }

    return minPeople;
}

int main() {
    int m;
    cin >> m; // 读取测试数据组数

    while (m--) {
        string s;
        cin >> s; // 读取每组的出入记录字符串
        cout << calculateMinPeople(s) << endl;
    }

    return 0;
}

六、关键易错点提醒

  1. 最初的人也要算:如果一个人最初就在餐厅里,在这段时间里他出去了,就算是"出入过餐厅"的人,需要计入总人数。
  2. 人员复用的顺序不影响结果:无论复用哪个人,最终的最少人数都是一样的,所以我们只需要计数,不需要跟踪具体是哪个人。
  3. 边界情况处理:输入全是'-'的情况(如"---"),答案就是字符串的长度,因为每个离开事件都需要一个最初的人。
相关推荐
gihigo19981 小时前
基于小波框架与稀疏表示的SAR图像目标识别系统(MATLAB实现)
算法
吴可可1231 小时前
CAD2004自定义实体开发环境配置
c++·算法
装不满的克莱因瓶1 小时前
矩阵的主成分是什么?主成分分析(PCA)又能做什么?
人工智能·线性代数·算法·机器学习·ai·矩阵·pca
大菜菜小个子1 小时前
template<typename T>使用
java·开发语言·算法
Fanfanaas2 小时前
C++ 继承
java·开发语言·jvm·c++·学习·算法
lqqjuly2 小时前
模型合并与融合:理论、算法与可运行实现—从损失曲面几何到多模型融合
算法
memcpy02 小时前
LeetCode 2144. 打折购买糖果的最小开销【贪心】
算法·leetcode·职场和发展
散峰而望3 小时前
【算法练习】算法练习精选:陶陶摘苹果(基础+升级)、Music Notes、字串变换,你能AC几道?
数据结构·c++·算法·leetcode·贪心算法·github·动态规划
暗夜猎手-大魔王3 小时前
转载--Hermes Agent 04 | Agent 主循环:一次对话背后发生了什么
人工智能·python·算法