首页 > 其他 > 详细

BFPRT

时间:2019-12-12 19:58:47      阅读:95      评论:0      收藏:0      [点我收藏+]

https://blog.csdn.net/qq_40938077/article/details/81213820#commentBox

"""
BFPRT算法,简称 TOP K 问题,用来求数组中第k小元素的算法
    - BFPRT是快速选择算法的改进版,改进了对基准的选取
    - 可以在O(n)时间内求出答案

    - Niubility !!
"""

import random


class Solution:
    # 快速选择排序算法,平均情况O(n),最坏情况O(n^2),还不错,不过还有更好的算法:BFPRT
    def findKthLargest(self, nums, k):
        def getmedian(lis):
            """返回lis中位数"""
            begin = 0
            end = len(lis)-1

            sum = begin+end
            mid = sum//2 + sum%2
            # print(lis)
            # print('返回:', sorted(lis)[mid])
            return sorted(lis)[mid]
        # int getmedian(int root[],int beginI,int endI)//这个函数求的是在root数组中beginI位置到endI位置上的中位数(其实就是求由每5个数所分成的小组的小组内的中位数)
        # {
        #     sort(root+beginI,root+endI+1);
        #     int sum=beginI+endI;
        #     int mid=(sum/2)+(sum%2);//这个地方加上sum%2是为了确保偶数个数时我们求的是中间两个数的后一个
        #     return root[mid];
        # }

        def BFPRT(nums, left, right):
            num = right-left+1
            offset = 0 if num % 5 == 0 else 1
            groups = num//5 + offset
            median = []  # 中位数数组
            for i in range(groups):
                begin = left+i*5
                end = begin + 4
                # print(nums[begin:min(end, right)+1])
                Median = getmedian(nums[begin:min(end, right)+1])
                median.append(Median)
            print("中位数数组:", median)
            return select(median, 0, groups-1, groups//2)
        # int medianOfMedians(int root[],int star,int finish)//这个函数是将root数组star位置到finish位置分成每5个数一个小组,并求出每个小组内的中位数
        # {
        #     int num=finish-star+1;//求出长度  【6】
        #     int offset=num%5==0?0:1;//最后如果剩余的数不足5个,我们也将其分成一个小组,和前面同等对待
        #     int range=num/5+offset; 【2组】
        #     int median[range];//这个数组存的是每个小组内的中位数
        #     for(int i=0;i<range;i++)//依次往median数组中填数
        #     {
        #         int beginI=star+i*5;//第i组数对应root数组上的位置
        #         int endI=beginI+4;
        #         median[i]=getmedian(root,beginI,min(endI,finish)); 【0-4】、【5-5】
        #     } median = [3, 4]
        #     return bfprt(median,0,range-1,range/2);//求出生成好的median数组的中位数,作为partation函数的划分值
        # }

        def partition(nums, left, right, base):
            """
            在 nums[left, right] 将基准base归位
            """
            temp = nums[base]
            nums[base], nums[right] = nums[right], nums[base]  # 基准和末尾元素互换

            max_index = left
            for i in range(left, right):  # 把所有小于基准的移到左边
                if nums[i] <= temp:  # 要等于啊!这里好坑的说..
                    nums[max_index], nums[i] = nums[i], nums[max_index]
                    max_index += 1

            nums[right], nums[max_index] = nums[max_index], nums[right]  # 基准归位
            return max_index

        def select(nums, left, right, k_smallest):
            """
            在 nums[left, right] 找第k小的元素
            """
            if left == right:  # 递归终止条件
                return nums[left]
            # pivot_index = random.randint(left, right)
            base = BFPRT(nums, left, right)
            print('找到的基准为', base, nums)
            base_index = nums.index(base)
            print(base_index)
            base_index = partition(nums, left, right, base_index)  # 选第一个(left)为基准,并归位。
            print("base_index:", nums)
            if base_index == k_smallest:  # 判断目前已归位的基准,是不是第k_smallest位
                return nums[k_smallest]
            elif k_smallest < base_index:  # 递归左半部分
                return select(nums, left, base_index - 1, k_smallest)
            else:  # 递归右半部分
                return select(nums, base_index + 1, right, k_smallest)
        ans = select(nums, 0, len(nums) - 1, len(nums) - k)  # 第k大,是第n-k小
        print(nums)
        return ans


s = Solution()
print(s.findKthLargest([3, 3, 3, 3, 4, 3, 3, 3, 3], 1))

BFPRT

原文:https://www.cnblogs.com/ldy-miss/p/12031077.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!