• 记录我对'我们有成熟的时间复杂度为O(n)的算法得到数组中任意第k大的数'的误解


    这篇博客记录我对剑指offer第2版"面试题39:数组中出现次数超过一半的数字"题解1的一句话的一个小误解,以及汇总一下涉及partition算法的相关题目。

    在剑指offer第2版"面试题39:数组中出现次数超过一半的数字"的解法一(基于partition,且哨兵选择数组第一个元素)中,有这么一句话:
    我们有成熟的时间复杂度为O(n)的算法得到数组中任意第k大的数字,这句话让我产生了一点误解,让我误以为"只需要调用一次partition就能找到第k大的数",但是实际上最差情况下需要调用n次partition函数才能找到第k大的数。因为partition每次都返回的是哨兵的位置,但是在函数运行过程中,随着l,r入参的变化,哨兵(数组首位元素)的位置是随之变化的,具有不确定性。

    所以基于partition获取数组中任意第k大元素的时间复杂度应该如下:

    1. 最好时间复杂度 O(1) : 第一次循环就找到正确的哨兵(即,第k大元素)
    2. 最差时间复杂度 n*O(n): 最后一次才找到正确的哨兵
    3. (加权)平均复杂度 这个我不太会算,估计是O(n)

    估算过程:
    3.1 加权平均复杂度 = 某概率值*O(n)
    3.2 概率值是常数,然后去掉常数项,得O(n)

    partition的Go代码如下:

    // partition代码的时间复杂度是O(n),因为需要通过for循环遍历数组,并把每个元素都划分到大分区或小分区中。
    func partition(nums []int, l, r int) int {
    	// 1. 哨兵 取第一个元素
    	v := nums[l]
    	// 2. 大小分区的定义和初始化 [l+1,p]<v && [p+1,cur-1]>v 
    	p := l
    	// 3. 处理哨兵之后的每一个元素
    	cur := l + 1
    	for ; cur <= r; cur++ {
    		if nums[cur] < v {
    			nums[cur], nums[p+1] = nums[p+1], nums[cur]
    			p++
    		}
    	}
    	nums[p], nums[l] = nums[l], nums[p] // 哨兵和小分区的最后一个元素交换,使得哨兵左边是小的,右边是大的.
    	return p
    }
    

    另外,还有以下这些算法题涉及了partition函数的运用,他们的共同特点都是需要用partition查找xxx位置的数字。

    1. Majority Element(本博客讨论的题) : partition查找m位置的数(中位数:索引为n/2)
    2. Kth Largest Element in an Array : partiton查找k位置的数
    3. 剑指offer面试题40:最小的k个数 : partiton查找k位置的数,但是只返回k位置左边的数,也就是小于哨兵的那些数
  • 相关阅读:
    swoole 入门
    Centos7安装Percona5.7
    clone github报Permission denied (publickey) 解决方案
    yii2-swiftmailer入门
    Yii 2.0 数据库操作总结
    面向对象简单示例
    面向对象与面向过程
    Tkinter之部件3种放置方式pack、grid、place
    Tkinter之variable用法
    Tkinter之Menu
  • 原文地址:https://www.cnblogs.com/yudidi/p/12148678.html
Copyright © 2020-2023  润新知