黄哥Python提醒: 只有学习过算法,才会慢慢的应用到工作中去

186 阅读3分钟
原文链接: zhuanlan.zhihu.com

有这样的一个面试题,求一个数组的第K 大值。

一般人会想到的是下面第一,二种方法,


第一种方法,先排序,再按照索引求值

'''
黄哥Python培训 黄哥所写
Python 3

'''


def get_k_max_value(lst, k):
    """先排序,再按照索引取值,时间复杂度是 O(n log n)"""
    lst.sort(reverse=True)
    return lst[k - 1]


if __name__ == '__main__':
    lst = [3, 7, 12, 2, 6, 18, 11, 9]
    k = 3
    print(get_k_max_value(lst, k))



第二种方法:


'''
黄哥Python培训 黄哥所写
Python 3

'''


def get_k_max_value(lst, k):
    '''先取k个元素到一个list中,再在剩下的len(lst) - k 中和
    排序好的lst1 中的最后一个元素比较,比它小抛弃,大,插入到相应位置。
    时间复杂度 O(klogk + n * klogk)
    '''
    lst1 = lst[0:k]
    lst2 = lst[k:]
    lst1.sort(reverse=True)
    for i in lst2:
        if i < lst1[-1]:
            continue
        else:
            lst1[-1] = i
            lst1.sort(reverse=True)
            print(lst1)

    return lst1[-1]


if __name__ == '__main__':
    lst = [3, 7, 12, 2, 6, 18, 11, 9]
    k = 3
    print(get_k_max_value(lst, k))



上面二种方法,如果数组元素有几百万之多,当k = 500000 时,上面二个算法都不能在合理的时间里完成。


第三种方法:


在计算机科学中,快速选择(英语:Quickselect)是一种从无序列表找到第k小元素的选择算法。它从原理上来说与快速排序有关。与快速排序一样都由托尼·霍尔提出的,因而也被称为霍尔选择算法。同样地,它在实际应用是一种高效的算法,具有很好的平均时间复杂度,然而最坏时间复杂度则不理想。快速选择及其变种是实际应用中最常使用的高效选择算法。快速选择的总体思路与快速排序一致,选择一个元素作为基准来对元素进行分区,将小于和大于基准的元素分在基准左边和右边的两个区域。不同的是,快速选择并不递归访问双边,而是只递归进入一边的元素中继续寻找。这降低了平均时间复杂度,从O(n log n)至O(n),不过最坏情况仍然是O(n2)。

与快速排序一样,快速选择一般是以原地算法的方式实现,除了选出第k小的元素,数据也得到了部分地排序。


该算法的伪代码


QuickSelect(A, k)
  let r be chosen uniformly at random in the range 1 to length(A)
  let pivot = A[r]
  let A1, A2 be new arrays
  # split into a pile A1 of small elements and A2 of big elements
  for i = 1 to n
    if A[i] < pivot then
      append A[i] to A1
    else if A[i] > pivot then
      append A[i] to A2
    else
      # do nothing
  end for
  if k <= length(A1):
    # it's in the pile of small elements
    return QuickSelect(A1, k)
  else if k > length(A) - length(A2)
    # it's in the pile of big elements
    return QuickSelect(A2, k - (length(A) - length(A2))
  else
    # it's equal to the pivot
    return pivot




'''
黄哥Python培训 黄哥修改
Python 3

'''
import random


def get_k_max_value(lst, k):
    '''时间复杂度O(n)'''
    if len(lst) == 0:
        return None
    pivot = random.choice(lst)
    lst1, lst2 = [], []
    for i in lst:
        if i > pivot:
            lst1.append(i)
        elif i < pivot:
            lst2.append(i)
    if k <= len(lst1):
        return get_k_max_value(lst1, k)
    elif k > len(lst) - len(lst2):
        return get_k_max_value(lst2, k - (len(lst) - len(lst2)))
    return pivot


if __name__ == '__main__':
    lst = [3, 7, 12, 2, 6, 18, 11, 9]
    k = 3
    print(get_k_max_value(lst, k))




总结: 如果没有学习过快速选择算法,一般人是想不到这个算法的,所以要学习已经发明的算法,并应用到工作中或面试中。

如果不学习算法,不会想到第三种方法,那么写出第一,二种算法的代码,就不会通过面试,所以一定要学习算法。

参考文章

TimeComplexity - Python Wiki

QuickSelect

https://zh.wikipedia.org/wiki/%E5%BF%AB%E9%80%9F%E9%80%89%E6%8B%A9


黄哥Python培训是这样训练学员的

黄哥Python培训是这样训练学员的


黄哥Python提醒:转行当程序员修炼之路

黄哥Python提醒:转行当程序员修炼之路


黄哥Python:提醒要转行当程序员的朋友,学习要分先后主次

黄哥Python:提醒要转行当程序员的朋友,学习要分先后主次