leetcode每日一题day20(24.9.30)——座位预约管理系统


思路:由于一直是出最小的编号,并且除此之外只有添加元素的操作,如果使用数组存储,并记录,这样出最小编号时间是O(n)复杂度,释放一个座位则是O(1)在操作出线机会均等的情况下,平均是O(n/2),

        但对于这种重复 出最大或最小,并添加元素,堆有更好的性能,

此处贴出自己实现的,堆排序,建堆可以优化,此时复杂度递推复杂度为T(n)=log2N+2T(n/2)

void adJustDown(int *pInt, int size) {//构建堆***********************************有问题可优化
    for (int read = 2; read <= size; read++) {//从第二个元素开始构造堆,以1为起始坐标
        int t = read;
        while (t != 1) {//调整到根时结束
            int fa = t % 2 == 0 ? t / 2 : (t - 1) / 2;//找到父亲
            if (pInt[t - 1] > pInt[fa - 1]) {//大于父亲进行调整,且由于下标0起需要在1起的情况下减一
                pInt[t - 1] ^= pInt[fa - 1];
                pInt[fa - 1] = pInt[t - 1] ^ pInt[fa - 1];
                pInt[t - 1] ^= pInt[fa - 1];
                t = fa;
            } else {//一次调整完成
                break;
            }
        }
    }
}

void Heapsort(int pInt[], int size) {
    adJustDown(pInt, size);
    int t = size;//以t指向未排序元素的最后一个元素
    while (t > 1) {
        pInt[t - 1] ^= pInt[0];//出最大元素,为了维持堆完全二叉树的性质将未排序的最后一个元素放到堆顶再进行向下调整
        pInt[0] = pInt[0] ^ pInt[t - 1];
        pInt[t - 1] ^= pInt[0];
        t -= 1;
        int i = 1;
        while (i <= t / 2) {//大于t/2就是叶子节点了
            int maxIdx =
                    i * 2 + 1 > t ? i * 2 : pInt[i * 2 - 1] > pInt[i * 2] ? i * 2 : i * 2 + 1;//孩子值中较大的一个的坐标考虑只有左孩子情况
            pInt[i - 1] ^= pInt[maxIdx - 1];//调整
            pInt[maxIdx - 1] = pInt[i - 1] ^ pInt[maxIdx - 1];
            pInt[i - 1] ^= pInt[maxIdx - 1];
            i = maxIdx;
        }
    }
}

堆的性质:

        一棵完全二叉树:所有它可以使用一维数组完美存储

(一个节点假设其存在X下标,其左孩子则存在2*X右孩子存在2*X+1,这样对于任一一个堆或者说完全二叉树都是可以用一个一维数组完美存下。)(可以尝试思考一下)

        根元素为所有元素中优先级最高的元素,每次对堆进行取值,都将取下根,可以使用将最后一个元素换上来,并再次调整堆,使取值后的堆仍可保持堆的性质

        上述排序操作即为,一直重复上一个操作,则可得到一个以优先级为顺序的序列而达到排序效果,


现在回归题目

       对于安排最小的座位,我们便可依据此,建立小顶堆,这样安排最小座位便是取根元素,取完进行调整,释放座位操作,可以理解为插入一个元素在数组末尾,并从尾到头进行调整便可。

当然也可使用内置api,这样只需理解大概,不需要了解如何实现。

class SeatManager {
public:
    vector<int> available;

    SeatManager(int n) {
        for (int i = 1; i <= n; ++i){
            available.push_back(i);
        }
    }
    
    int reserve() {
        pop_heap(available.begin(), available.end(), greater<int>());
        int tmp = available.back();
        available.pop_back();
        return tmp;
    }
    
    void unreserve(int seatNumber) {
        available.push_back(seatNumber);
        push_heap(available.begin(), available.end(), greater<int>());
    }
};

这样 分配座位的时间就分摊到,释放座位上了,时间复杂度都是,O(log2N)

但在正确的操作下,建堆需要O(N)时间,我堆排序的建堆过程随能达到效果但冗余过多

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值