LeetCode《程序员面试金典》面试题 03.06. 动物收容所

本文详细解析了LeetCode中关于动物收容所的面试题,重点讨论如何实现“dequeueAny”功能,即找到并移除猫和狗中最老的动物。解题过程中涉及到了数组操作、数组转链表以及使用splice和shift等方法的注意事项,旨在提高编程技巧和理解数据结构的应用。
摘要由CSDN通过智能技术生成

LeetCode 面试题 03.06. 动物收容所

题目

在这里插入图片描述
“最老”可以用编号来比较,编号越小,代表越老,题目已经给了动物编号,如果没有需要自己创建编号或者记录时间戳。

"dequeueAny" 是要 dequeue 猫和狗中最老的。

解题

解题一

在这里插入图片描述

// javascript
var AnimalShelf = function() {
    this.queueAnimal = [];
};

/** 
 * @param {number[]} animal
 * @return {void}
 */
AnimalShelf.prototype.enqueue = function(animal) {
    this.queueAnimal.push(animal);
};

/**
 * @return {number[]}
 */
AnimalShelf.prototype.dequeueAny = function() {
    let ret = [-1, -1];
    if (this.queueAnimal.length !== 0) {
        ret = this.queueAnimal.shift();
    }
    return ret;
};

/**
 * @return {number[]}
 */
AnimalShelf.prototype.dequeueDog = function() {
    let ret = [-1, -1];
    for (let index = 0; index < this.queueAnimal.length; index++) {
        if (this.queueAnimal[index][1] === 1) {
            ret = this.queueAnimal.splice(index, 1)[0];
            break;
        }
    }
    return ret;
};

/**
 * @return {number[]}
 */
AnimalShelf.prototype.dequeueCat = function() {
    let ret = [-1, -1];
    for (let index = 0; index < this.queueAnimal.length; index++) {
        if (this.queueAnimal[index][1] === 0) {
            ret = this.queueAnimal.splice(index, 1)[0];
            break;
        }
    }
    return ret;
};

需要注意的是,JS 中 Array 的 splice 函数返回的是一个包含所有被删除元素的数组,本身这里存储的每个元素都是 [编号,猫或狗],所以获取被删除元素时要加索引 [0]。

解题二

在这里插入图片描述

// javascript
var AnimalShelf = function() {
    this.cat = [];
    this.dog = [];
};

/** 
 * @param {number[]} animal
 * @return {void}
 */
AnimalShelf.prototype.enqueue = function(animal) {
    if (animal[1] === 0) {
        this.cat.push(animal);
    }
    else {
        this.dog.push(animal);
    }
};

/**
 * @return {number[]}
 */
AnimalShelf.prototype.dequeueAny = function() {
    if (this.cat.length === 0) return this.dequeueDog();
    if (this.dog.length === 0) return this.dequeueCat();
    let catIdx = this.cat[0][0], dogIdx = this.dog[0][0];
    if (catIdx < dogIdx) {
        return this.dequeueCat();
    }
    else {
        return this.dequeueDog();
    }
};

/**
 * @return {number[]}
 */
AnimalShelf.prototype.dequeueDog = function() {
    if (this.dog.length === 0) return [-1, -1];
    return this.dog.shift();
};

/**
 * @return {number[]}
 */
AnimalShelf.prototype.dequeueCat = function() {
    if (this.cat.length === 0) return [-1, -1];
    return this.cat.shift();
};

记录下面的写法纯粹是为了熟悉 array of arrays 的操作:

// javascript
var AnimalShelf = function() {
    this.queueAnimal = [[], []];
};

/** 
 * @param {number[]} animal
 * @return {void}
 */
AnimalShelf.prototype.enqueue = function(animal) {
    let [order, group] = animal;
    this.queueAnimal[group].push(order);
};

/**
 * @return {number[]}
 */
AnimalShelf.prototype.dequeueAny = function() {
    let [queueCat, queueDog] = this.queueAnimal;
    if (queueDog.length === 0) return this.dequeueCat(); // 没有待领养的狗
    if (queueCat.length === 0) return this.dequeueDog(); // 没有待领养的猫
    const oldestDogIdx = queueDog[0], oldestCatIdx = queueCat[0];
    // 比较最老的狗和最老的猫谁更老
    if (oldestDogIdx < oldestCatIdx) {
        return this.dequeueDog();
    }
    else {
        return this.dequeueCat();
    }
};

/**
 * @return {number[]}
 */
AnimalShelf.prototype.dequeueDog = function() {
    let ret = [-1, -1];
    let [ , queueDog] = this.queueAnimal;
    if (queueDog.length !== 0) {
        ret = [queueDog.shift(), 1];
    }
    return ret;
};

/**
 * @return {number[]}
 */
AnimalShelf.prototype.dequeueCat = function() {
    let ret = [-1, -1];
    let [queueCat, ] = this.queueAnimal;
    if (queueCat.length !== 0) {
        ret = [queueCat.shift(), 0];
    }
    return ret;
};

上述解法有一个要学习的地方是 多赋有意义的变量名,因为 queueAnimal 数组里包含数组,属于 Array of arrays,如果想把编号和类型数组直接存进猫或狗的数组中,会变成 三层数组:queueAnimal 数组由 猫数组 和 狗数组 组成,猫 / 狗数组里的元素也是数组,语义不明显的话写起来容易错,别人读的时候光看见 [0][0][0],也不明白其中含义。

解题三

用数组做 shift 时会把剩余元素都前移一位,效率不高,自己写了一个 LinkedList 的方法。

// javascript
var ListNode = function (val) {
    this.val = val;
    this.next = null;
};

var AnimalShelf = function() {
    this.dogHead = this.dogTail = new ListNode(0);
    this.catHead = this.catTail = new ListNode(0);
};

/** 
 * @param {number[]} animal
 * @return {void}
 */
AnimalShelf.prototype.enqueue = function(animal) {
    let newNode = new ListNode(animal);
    if (animal[1] === 0) {
        this.catTail.next = newNode;
        this.catTail = this.catTail.next;
    }
    else {
        this.dogTail.next = newNode;
        this.dogTail = this.dogTail.next;
    }
};

/**
 * @return {number[]}
 */
AnimalShelf.prototype.dequeueAny = function() {
    if (this.dogHead.next === null) return this.dequeueCat();
    if (this.catHead.next === null) return this.dequeueDog();
    if (this.dogHead.next.val[0] < this.catHead.next.val[0]) {
        return this.dequeueDog();
    }
    else {
        return this.dequeueCat();
    }
};

/**
 * @return {number[]}
 */
AnimalShelf.prototype.dequeueDog = function() {
    let ret = [-1, -1];
    if (this.dogHead.next !== null) {
        ret = this.dogHead.next.val;
        this.dogHead.next = this.dogHead.next.next;
        // 如果 队列 空了(只剩下伪头节点),把 tail 指针重新指回 head
        if (this.dogHead.next === null) {
            this.dogTail = this.dogHead;
        }
    }
    return ret;
};

/**
 * @return {number[]}
 */
AnimalShelf.prototype.dequeueCat = function() {
    let ret = [-1, -1];
    if (this.catHead.next !== null) {
        ret = this.catHead.next.val;
        this.catHead.next = this.catHead.next.next;
        if (this.catHead.next === null) {
            this.catTail = this.catHead;
        }
    }
    return ret;
};

写的时候犯了些错误,一是注意 dequeue 中如果队列空了(只剩下伪头节点),要把 tail 指针重新指回 head,否则 tail 还指着被删除的节点,而 head.next 已经为 null,enqueue 时会往 tail 后面加新节点,head 再也找不到这些节点。

还有大概是脑子糊掉了,竟然写出 this.cat.head 这种鬼 T.T。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值