📜  门| GATE CS 2019 |第 31 题(1)

📅  最后修改于: 2023-12-03 14:58:20.294000             🧑  作者: Mango

门 | GATE CS 2019 | 第31题

本题是 GATE CS 2019 的 31 题,属于算法和数据结构部分。

题目描述

有一个门,由两个木板组成。第一个木板可以旋转,打开和关闭,并且在打开和关闭时会发出一个声音。第二个木板是静止不动的。

在门打开之前,第一个木板可以处于两种状态之一:1) 向上,2) 向下。一旦第一个木板打开,它会自动保持在打开状态,直到第二个木板被关闭,然后第一个木板可以再次打开。

编写一个函数 minMoves(int arr[], int n),它将 n 个数字的数组作为输入,并返回需要的最小移动次数,以便通过唤醒第一个木板来打开门。在唤醒第一个木板之前,所有数字都必须被按顺序读取。

每次移动可以将一个数字从数组的前面移动到后面。初始时,所有数字都位于数组的起始位置。如果数组中的所有数字以正确的顺序读取,直到第二个木板关闭,那么一次移动的最小数量是什么?

输入和输出

输入为一个数组 arr[] 和它的长度 n

输出为一个整数,表示需要的最小移动次数。

举例
minMoves([3, 4, 1, 2, 5], 5) = 4
解法

这个问题可以使用队列来解决。我们将所有未读数字存储在一个队列中,同时维护一个指向第一个木板上的数字的指针。我们还记录了第一个木板的状态(向上或向下)以及木板是否已打开。

当我们读取队列中的下一个数字时,我们需要扫描该数字之后的所有数字。如果在所有数字中存在比该数字更小的数字,则我们需要将该数字从队列中移到末尾,直到它被正确定位。

如果此时第一个木板没有打开,则将其唤醒。如果第二个木板没有关闭,则继续读取队列中的数字。否则,我们已经完成了所有必要的移动,可以退出循环并返回移动的次数。

代码

以下是使用 C++ 语言实现的代码示例:

#include <iostream>
#include <queue>
using namespace std;

bool isOpen = false;
bool isUp = true;

int minMoves(int arr[], int n) {
    int cnt = 0;
    queue<int> q;
    for (int i = 0; i < n; i++) {
        q.push(arr[i]);
    }

    while (!q.empty()) {
        if (q.front() == 1 && !isOpen) {
            isOpen = true;
            cnt++;
        } else if (q.front() == 2 && isOpen) {
            isOpen = false;
            cnt++;
            if (q.empty()) {
                return cnt;
            }
            q.pop();
            if (q.front() != 1 && isUp) {
                isUp = false;
                cnt++;
            }
            continue;
        }

        int cur = q.front();
        bool flag = true;
        q.pop();
        int size = q.size();
        for (int i = 0; i < size; i++) {
            int temp = q.front();
            q.pop();
            if (temp < cur) {
                flag = false;
            }
            q.push(temp);
        }

        if (!flag) {
            q.push(cur);
            continue;
        }

        cnt++;
        if (q.empty()) {
            return cnt;
        }

        q.pop();
        if (q.front() != 1 && isUp) {
            isUp = false;
            cnt++;
        }
    }

    return cnt;
}

int main() {
    int arr[] = {3, 4, 1, 2, 5};
    int n = sizeof(arr) / sizeof(arr[0]);

    cout << minMoves(arr, n) << endl;

    return 0;
}
时间复杂度

时间复杂度为 O(n^2),其中 n 是输入数组的长度。代码中的循环嵌套是 O(n^2) 的,因此总时间复杂度为 O(n^2)。但是,如果我们使用一个更高效的数据结构,如链表或双端队列,我们可以将这个时间复杂度降低到 O(nlogn)。

空间复杂度

空间复杂度为 O(n),其中 n 是输入数组的长度。我们使用了一个队列来存储剩余的数字。