📜  门| GATE CS 2018 |简体中文问题29(1)

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

门 | GATE CS 2018 | 简体中文问题29

在这个问题中,我们需要设计一个算法来查找数组中第二个最小的元素。具体来说,我们需要实现以下函数:

def second_smallest(arr: List[int]) -> int:
    pass
输入
  • arr:一个整数数组,长度为 $n$($2 \leq n \leq 10^6$),数组中的元素均为互不相同的整数。
输出
  • 返回数组中第二个最小的元素。
示例
assert second_smallest([10, 5, 4, 3, 1]) == 3
assert second_smallest([2, 3, 1, 4]) == 2
assert second_smallest([5, 6, 2, 1, 7, 9]) == 2
思路

我们可以使用类似快排的思路解决这个问题。具体来说,我们可以先选定一个数字为基准,将比它小的数字移动到它左边,比它大的数字移动到它右边。然后根据基准的位置,分别在基准的左侧和右侧进行递归查找,直到找到第二个最小的元素。

具体实现时,我们可以选择数组中的第一个元素为基准,然后使用 partition 函数进行划分。partition 函数将会返回一个整数,表示基准最终所在的位置。如果这个位置满足它左侧恰好有一个元素,那么这个元素就是第二个最小的元素;否则我们需要递归查找。

from typing import List


def second_smallest(arr: List[int]) -> int:
    def partition(low: int, high: int) -> int:
        pivot = arr[low]
        i, j = low + 1, high
        while i <= j:
            while i <= high and arr[i] < pivot:
                i += 1
            while j >= low + 1 and arr[j] > pivot:
                j -= 1
            if i <= j:
                arr[i], arr[j] = arr[j], arr[i]
                i += 1
                j -= 1
        arr[low], arr[j] = arr[j], arr[low]
        return j

    def find(pos: int, low: int, high: int) -> int:
        if pos == 1:
            return arr[low]
        pivot_pos = partition(low, high)
        pivot_rank = pivot_pos - low + 1
        if pos == pivot_rank:
            return arr[pivot_pos]
        elif pos < pivot_rank:
            return find(pos, low, pivot_pos - 1)
        else:
            return find(pos - pivot_rank, pivot_pos + 1, high)

    return find(2, 0, len(arr) - 1)
复杂度分析
  • 时间复杂度:$O(n)$
  • 空间复杂度:$O(1)$

由于 partition 函数的调用次数最多为 $O(n)$,因此总的时间复杂度为 $O(n)$。同时在递归调用中并没有额外的空间开销,因此空间复杂度为 $O(1)$。