大厂高频经典面试题(23)-队列应用场景

1. 题目:

有家动物收容所只收容狗与猫,且严格遵守“先进先出”的原则。在收养该收容所的动物时,收养人只能收养所有动物中“最老”(由其进入收容所的时间长短而定)的动物,或者可以挑选猫或狗(同时必须收养此类动物中“最老”的)。换言之,收养人不能自由挑选想收养的对象。请创建适用于这个系统的数据结构,实现各种操作方法,比如 enqueue、dequeueAny、dequeueDog 和 dequeueCat。

2. 解题思路:

使用两个独立的队列分别存储狗和猫。
每个动物进入时都会记录精确的时间戳。

图解下面代码的整个过程:

1.初始状态

动物收容所:
狗队列: []
猫队列: []

2.收容动物流程 (enqueue)

1. 收容Buddy(狗)
狗队列: [Buddy(ts=1)]
猫队列: []

2. 收容Fluffy(猫)
狗队列: [Buddy(ts=1)]
猫队列: [Fluffy(ts=2)]

3. 收容Max(狗)
狗队列: [Buddy(ts=1), Max(ts=3)]
猫队列: [Fluffy(ts=2)]

4. 收容Mittens(猫)
狗队列: [Buddy(ts=1), Max(ts=3)]
猫队列: [Fluffy(ts=2), Mittens(ts=4)]

3.收养流程 (dequeue)

1. dequeueAny():
   比较Buddy(ts=1)和Fluffy(ts=2)
   选择Buddy(最早)
狗队列: [Max(ts=3)]
猫队列: [Fluffy(ts=2), Mittens(ts=4)]

2. dequeueCat():
   选择Fluffy(猫队列最早)
狗队列: [Max(ts=3)]
猫队列: [Mittens(ts=4)]

3. dequeueDog():
   选择Max(狗队列最早)
狗队列: []
猫队列: [Mittens(ts=4)]

3. 代码完整实现(C++):

#include <chrono>
#include <iostream>
#include <queue>
#include <string>
#include <thread>

class Animal {
   protected:
    std::string name;
    int64_t orderTs;  // 用于记录动物进入收容所的时间(unix毫秒)
   public:
    Animal(const std::string& n) : name(n) {}
    virtual ~Animal() = default;
    void setOrderTs(int64_t ts) { orderTs = ts; }
    int64_t getOrderTs() { return orderTs; }
    std::string getName() const { return name; }

    // 重载<运算符,用于优先队列比较
    bool operator<(const Animal& other) const {
        // 较小的order表示更早进入
        return this->orderTs < other.orderTs;
    }
};

class Dog : public Animal {
   public:
    Dog(const std::string& n) : Animal(n) {}
};

class Cat : public Animal {
   public:
    Cat(const std::string& n) : Animal(n) {}
};

class AnimalShelter {
   private:
    std::queue<std::unique_ptr<Dog>> dogs;
    std::queue<std::unique_ptr<Cat>> cats;

   public:
    AnimalShelter() {}

    // 收容动物
    void enqueue(std::unique_ptr<Animal> animal) {
        // 获取当前时间点
        auto now = std::chrono::system_clock::now();
        // 计算unix时间戳的毫秒数
        int64_t nowTs = std::chrono::duration_cast<std::chrono::milliseconds>(
                            now.time_since_epoch())
                            .count();
        animal->setOrderTs(nowTs);

        if (dynamic_cast<Dog*>(animal.get())) {
            // 转移所有权到dogs队列
            dogs.push(
                std::unique_ptr<Dog>(static_cast<Dog*>(animal.release())));
        } else if (dynamic_cast<Cat*>(animal.get())) {
            cats.push(
                std::unique_ptr<Cat>(static_cast<Cat*>(animal.release())));
        }
    }

    // 收养所有动物中最老的
    std::unique_ptr<Animal> dequeueAny() {
        if (dogs.empty() && cats.empty()) {
            return nullptr;
        } else if (dogs.empty()) {
            return dequeueCat();
        } else if (cats.empty()) {
            return dequeueDog();
        }

        Dog* dog = dogs.front().get();
        Cat* cat = cats.front().get();
        if (*dog < *cat) {
            return dequeueDog();
        } else {
            return dequeueCat();
        }
    }

    // 收养最老的狗
    std::unique_ptr<Dog> dequeueDog() {
        if (dogs.empty()) {
            return nullptr;
        }
        auto dog = std::move(dogs.front());
        dogs.pop();
        return dog;
    }

    // 收养最老的猫
    std::unique_ptr<Cat> dequeueCat() {
        if (cats.empty()) {
            return nullptr;
        }
        auto cat = std::move(cats.front());
        cats.pop();
        return cat;
    }
};

int main() {
    AnimalShelter shelter;

    // 收容动物
    shelter.enqueue(std::make_unique<Dog>("Buddy"));
    std::this_thread::sleep_for(std::chrono::milliseconds(5));
    shelter.enqueue(std::make_unique<Cat>("Fluffy"));
    std::this_thread::sleep_for(std::chrono::milliseconds(5));
    shelter.enqueue(std::make_unique<Dog>("Max"));
    std::this_thread::sleep_for(std::chrono::milliseconds(5));
    shelter.enqueue(std::make_unique<Cat>("Mittens"));

    // 收养最老的动物(应该是Buddy)
    auto a = shelter.dequeueAny();
    if (a)
        std::cout << "收养了: " << a->getName() << std::endl;

    // 收养最老的猫(应该是Fluffy)
    auto c = shelter.dequeueCat();
    if (c)
        std::cout << "收养了猫: " << c->getName() << std::endl;

    // 收养最老的狗(应该是Max)
    auto d = shelter.dequeueDog();
    if (d)
        std::cout << "收养了狗: " << d->getName() << std::endl;

    return 0;
}

4. 代码分析:

这个实现严格遵循了题目要求:

  • 只使用队列结构
  • 支持按类型或全部收养
  • 保证总是收养最老的动物
  • 使用智能指针避免内存泄漏

时间复杂度:
enqueue: O(1)
dequeueAny: O(1)
dequeueDog/dequeueCat: O(1)

空间复杂度:
O(n),需要存储所有动物

5. 运行结果:

养了: Buddy
收养了猫: Fluffy
收养了狗: Max

感谢您的阅读。原创不易,如您觉得有价值,请点赞,关注。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水草

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值