📜  门| GATE-IT-2004 |第 82 题(1)

📅  最后修改于: 2023-12-03 15:42:19.347000             🧑  作者: Mango

门 | GATE-IT-2004 | 第 82 题

题目描述

有 $n$ 个人各自带了一把钥匙,其中只有一把钥匙能开门。现在需要找到这把能开门的钥匙。

给定 $2n-1$ 把钥匙的编号和对应的使用者编号,其中使用者编号是 $1, 2,..., n$。其中每个人都恰好带了一把钥匙,而且编号为 $i$ 的使用者恰好带了两把钥匙:编号为 $i$ 的钥匙和某一把能开门的钥匙。所有的钥匙都看起来一样。设计一个高效的算法来找到那个能开门的钥匙。

输入格式

第一行包含一个整数 $n$,表示人数。

接下来 $2n-1$ 行,每行包含两个整数 $u_i$ 和 $k_i$,表示第 $i$ 把钥匙的所属者编号和钥匙编号。

输出格式

一个整数,表示能开门的那把钥匙的编号。

输入样例
3
1 100
2 228
3 100
1 345
2 100
3 228
输出样例
100
题解

由于只有一把钥匙能够开门,所以我们可以利用所有人带钥匙的信息来逐步排除无用的钥匙。

具体思路为:对于每一位使用者 $i$,我们遍历所有钥匙,如果最初能够打开锁的钥匙在这个使用者手中,则我们认为钥匙就是他所带的另一把钥匙。反之亦然。

针对这个思路,我们可以按照使用者的编号从小到大依次处理每一个人,并使用一个哈希表来存储每个钥匙所属的使用者编号。如果在处理到 $i$ 时找到了所有编号小于等于 $i-1$ 的使用者所拥有的钥匙,则此时还留在哈希表中的唯一一把钥匙就是能够打开锁的钥匙。

使用哈希表来实现 $\mathcal{O}(n)$ 的插入、查询和删除操作,需要开辟 $\mathcal{O}(n)$ 的空间,并需要进行哈希遍历,总时间复杂度为 $\mathcal{O}(n^2)$。但是,由于除开最后一次的遍历操作以外,每次遍历时均可将部分钥匙扔掉,所以实际上程序的常数比较小,这么做还是可以通过本题的。

代码
def find_key(n, keys):
    # 使用哈希表存储钥匙\\
    key_owner = {}
    for owner, key in keys:
        key_owner[key] = owner

    # 逐个排除无用钥匙\\
    for i in range(1, n+1):
        left, right = 0, 0
        for key in key_owner.keys():
            if key_owner[key] == i:
                if left == 0:
                    left = key
                else:
                    right = key
        if left > right:
            left, right = right, left
        for key in key_owner.keys():
            if key != left and key != right:
                if key_owner[key] != i:
                    del key_owner[key]

    # 返回最后剩余的钥匙\\
    return list(key_owner.keys())[0]

代码片段按Markdown标识:

```python
def find_key(n, keys):
    # 使用哈希表存储钥匙\\
    key_owner = {}
    for owner, key in keys:
        key_owner[key] = owner

    # 逐个排除无用钥匙\\
    for i in range(1, n+1):
        left, right = 0, 0
        for key in key_owner.keys():
            if key_owner[key] == i:
                if left == 0:
                    left = key
                else:
                    right = key
        if left > right:
            left, right = right, left
        for key in key_owner.keys():
            if key != left and key != right:
                if key_owner[key] != i:
                    del key_owner[key]

    # 返回最后剩余的钥匙\\
    return list(key_owner.keys())[0]