返回

解剖面试高频题:破解LeetCode 786. 第 K 个最小的素数分数

后端

在计算机科学的领域里,算法和数据结构是两颗璀璨的明珠。它们为我们提供了解决复杂问题的工具和方法,帮助我们驾驭浩瀚的数据海洋。而 LeetCode 正是一个绝佳的平台,让我们在实战中磨砺算法和数据结构的技能,为职业发展奠定坚实的基础。

今天,我们将共同面对一道经典的面试笔试题——LeetCode 786. 第 K 个最小的素数分数。这道题不仅考察了算法的效率和正确性,更考验了我们对数据结构的理解和运用。

题目

给定两个正整数 NK,你需要找到第 K 个最小的分数 a / b,其中 ab 都是 1N 之间的正整数,且 a / b 是一个真分数(即 a < b)。

例如,当 N = 2K = 2 时,第 2 个最小的分数是 1 / 2

算法分析

这道题看似复杂,但其实我们可以通过巧妙地运用优先队列来求解。

首先,我们需要定义一个自定义的比较器,用来比较两个分数的大小。我们可以使用 a / bc / d 的差值作为比较的依据。如果 a / b 小于 c / d,那么 a / b 就更小;反之亦然。

接下来,我们将分数对 (a, b) 存储在优先队列中,其中 ab 都是 1N 之间的正整数,且 a < b。初始时,优先队列中只包含一个分数对 (1, N)

然后,我们不断地从优先队列中取出分数对 (a, b),并将其与 (a + 1, b)(a, b - 1) 这两个分数对进行比较。如果这三个分数对中,(a, b) 是最小的,那么我们就将其作为第 K 个最小的分数并返回。否则,我们将 (a + 1, b)(a, b - 1) 这两个分数对插入优先队列中,并继续执行此过程,直到我们找到第 K 个最小的分数。

代码实现

from queue import PriorityQueue

def kthSmallestPrimeFraction(N, K):
    # 定义自定义比较器
    def compare(x, y):
        return (x[0] * y[1]) - (x[1] * y[0])

    # 初始化优先队列
    pq = PriorityQueue(key=compare)
    
    # 将 (1, N) 插入优先队列
    pq.put((1, N))

    # 不断从优先队列中取出分数对
    while K > 1:
        # 取出分数对 (a, b)
        a, b = pq.get()
        
        # 将 (a + 1, b) 和 (a, b - 1) 插入优先队列
        if a + 1 <= b:
            pq.put((a + 1, b))
        if b - 1 >= 1:
            pq.put((a, b - 1))
        
        # 递减 K
        K -= 1
    
    # 返回第 K 个最小的分数
    return pq.get()

# 测试代码
N = 3
K = 3
result = kthSmallestPrimeFraction(N, K)
print(result)

总结

通过这道题,我们不仅学习了优先队列的用法,还锻炼了算法分析和代码实现的能力。更重要的是,我们认识到算法和数据结构是计算机科学的基石,它们在我们的职业发展中扮演着至关重要的角色。

作为一名技术博客创作专家,我致力于用独树一帜的观点展现事物,以此为基础构建文章。我希望这篇文章能给你带来启发,激励你在算法和数据结构的领域继续探索,不断提升自己的技能。