leetcode常见面试题总结 Python

发布时间:2024年01月22日

持续维护中...

1. 寻找 k 个最小数

输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

示例:

输入:arr = [3,2,1], k = 2

输出:[1,2] 或者 [2,1]

该问题最简单的方式就是直接对 arr 进行排序,然后取前 k 个数值。但其实有时间复杂度更优的方案,就是部分排序,只是找到前 k 个最小值即可。

def findSmallKnum(arr, k):
    for i in range(k):
        for j in range(i+1, len(arr)):
            if arr[i] > arr[j]:
                arr[i], arr[j] = arr[j], arr[i]
    return arr[:k]

2. 寻找两个正序数组的中位数

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数 。算法的时间复杂度应该为 O(log(m+n)) 。

示例:

输入:nums1 = [1,3], nums2 = [2]

输出:2? ? ? 解释:合并数组 = [1,2,3] ,中位数 2

该问题可以转换为求两个有序数组的第 k 最小值问题,需要用到一个第 k 最小值规律。这个规律为针对两个有序数组 A 和 B,如果 A 中的第 m 个数据 A(m-1) 大于 B 中的第 n 个数据 B(n-1),那可以保证两个有序数组的总数组 C 的第 m+n 个数据 C(m+n-1) 一定大于 B(n-1) 。可以用反正法证明,如果?C(m+n-1) 小于等于 B(n-1),那数组 B 中小于 C(m+n-1) 的数据个数一定小于等于 n-1,数组 A 中小于 C(m+n-1) 的数据个数一定小于等于 m-1,所以在总数据 C 中小于 C(m+n-1) 的个数小于 m+n-2 (m-1 与 n-1 不能同时获取),而实际情况是小于?C(m+n-1) 的数据个数是 m+n-1,所以证明结束。所以解该题目的思路为,假定在总数组中中位数是第 k 个数据,那就分别在 nums1 和 nums2 中比较第 k/2 个数值,然后基于第 k 最小值规律可以从某数组中剔除 k/2 个数据,然后接下来继续寻找剩余两个数组的第 k/2 最小值,以此类推,寻找 k/4、k/8、k/16...,直至 1 或者某数组中所有数据均已被剔除,所以时间复杂度可以做到 O(log(m+n))。但实际编程中需要考虑 k 是整数并非浮点数,如何取整和处理边界条件,以及数据索引与数据个数之间的关系。

def findMedianSortedArrays(nums1, nums2):
 
        def getK2(k):                                          # 定义一个函数实现查询的第 k 和 k+1 大的值,k 值不能太大
            id1, id2 = 0, 0                                    # 数组 1 和 2 的寻找起始索引,包含当前索引位置
            while True:                                        # id1 和 id2 是起始索引,k 是第几个值,所以 k 在变索引时需要减一
                # 终止条件
                if id1 == m:                                   # 数组 1 中的值已被全部剔除
                    return nums2[id2+k-1], nums2[id2+k]        # 在数组 2 中寻找起于 id2 的第 k 个值,k 变索引需要减一
                if id2 == n:                                   # 数组 2 中的值已被全部剔除
                    return nums1[id1+k-1], nums1[id1+k]        # 在数组 1 中寻找起于 id1 的第 k 个值,k 变索引需要减一
                if k == 1:                                     # k 等于 1 时,第 k 最小值,只需要找 min(nums1[id1],nums2[id2])
                    if nums1[id1] < nums2[id2]:                # 但第 k+1 个值比较麻烦,需要增加一些判断条件,分类处理
                        if id1 == m-1:
                            return nums1[id1], nums2[id2]
                        else:
                            return nums1[id1], min(nums1[id1+1], nums2[id2])
                    else:
                        if id2 == n-1:
                            return nums2[id2], nums1[id1]
                        else:
                            return nums2[id2], min(nums2[id2+1], nums1[id1])
 
                # 二分法遍历
                newid1 = min(id1+k//2-1, m-1)                  # 数组 1 需要判断的数值索引,对 k 的奇偶没有要求,但必须减一。如果不减一,会造成多剔除数据,漏掉结果,原因是 k//2 是第几个数不是索引
                newid2 = min(id2+k//2-1, n-1)                  # 变成索引需要减一。也不能减 2,原因是 k 大于等于 2,当 K==2 时,k//2-2 变负值了,其需要大于等于零
                p1, p2 = nums1[newid1], nums2[newid2]          # 根据第 k 最小值订定理,其实上面语句需要保证 [(id1+k//2-x)+1]+[(id2+k//2-x)+1] 小于等于 id1+id2+k,所以 x>=1,这用来解释为何减一,这是本代码最难的部分!!!
                if p1 <= p2:                                   # 若数组 1 的当前判断值较小,则说明判断下标以及之前的值全部都在中值左边,全部排除
                    k -= newid1 - id1 + 1                      # k 需要减去之前剔除的值的数量
                    id1 = newid1 + 1                           # 数组 1 从去除的索引后一位重新开始
                else:                                          # 同理
                    k -= newid2 - id2 + 1
                    id2 = newid2 + 1
   
        m,  n = len(nums1), len(nums2)   # 数组 1,数组 2 的长度
        Length = m + n                   # 两个数组总长度
        v1, v2 = getK2(Length//2)        # 通过 getK2 函数获取 Length//2 和 Length//2+1 对应的数值

        if Length%2 == 1:                # 若总数组长度为奇数,则使用 Length//2+1 对应的数值
            return v2
        else:                            # 若总数组长度为偶数,则使用 Length//2 和 Length//2+1 对应数值的均值
            return (v1+v2)/2

文章来源:https://blog.csdn.net/BIT_Legend/article/details/135482474
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。