• 【BFPRT】数组中出现次数超过一半的数字


    题目

    数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
    例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
    如果不存在则输出0。

    解答

    1, 一个数在序列中出现次数超过一半,那这个数排序后一定也出现在中位数的位置上,这样的话就变成了求解一个序列的第K大的数,其中K=length/2;【BFPRT, Time: O(N), Space: log(N))】
    2, 记录每个数出现的次数,最好情况遍历前n/2+1个即可,最差O(N), Space: O(N)
    3, 要找的数字出现的次数比其他数字出现次数的和还多1,遍历,相同叠加,相异抵消,最后的次数还为1的数字即是。Time: O(N), Space: O(1)

    三种方法都不错。还有一种无脑的排序,取中位数即可,排序用快排,时间复杂度N·log(N)
    讲一下BFPRT的空间复杂度,select分治过程用到递归,需要栈空间存储,递归次数即是栈空间大小,由于每次只处理划分后的一半,因此最差情况需要递归log(N)次,空间复杂度为log(N)

    本题还考察思维的全面性,除了实现功能以外,也应该对无效的输入进行响应的处理,因此有了核实操作。

    代码实现:

    # class Solution:
    #     # 方法1
    #     def get_median(self, nums):
    #         '''计算5个数的中位数'''
    #         begin, end = 0, len(nums) - 1
    # 
    #         sum = begin + end
    #         mid = sum // 2 + sum % 2  # 这个地方加上sum%2是为了确保偶数个数时我们求的是中间两个数的后一个
    #         return sorted(nums)[mid]  # 常量级别,影响不大,也可改用插入排序
    # 
    #     def BFPRT(self, nums, left, right):
    #         '''选择partition基准: 划分每5个一组,求每组的中位数'''
    #         num = right-left + 1
    #         offset = 0 if num % 5 == 0 else 1  # 最后如果剩余的数不足5个,我们也将其分成一个小组,和前面同等对待
    #         group = num//5 + offset
    # 
    #         median = []  # 中位数数组
    #         for i in range(group):
    #             begin = left + i * 5
    #             end = begin + 4
    #             Median = self.get_median(nums[begin:min(end, right) + 1])
    #             median.append(Median)
    #         return self.get_median(median)  # 这里是求中位数数组的中位数,再调用getmedian不就行了,为啥有的人还要用下面递归select,虽然也是正确的,但直接getmedian快一点啊
    #         # return select(median, 0, groups-1, groups//2)  # 求出生成好的median数组的中位数,作为partation函数的划分值
    # 
    #     def partition(self, nums, left, right, base):
    #         '''将基准base归位'''
    #         if left >= right:
    #             return
    # 
    #         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[max_index], nums[right] = nums[right], nums[max_index]
    #         return max_index
    # 
    #     def select(self, nums, left, right, K):
    #         '''快速选择过程'''
    #         if left == right:
    #             return nums[left]
    # 
    #         base = self.BFPRT(nums, left, right)                              # 选择基准
    #         base_index = self.partition(nums, left, right, nums.index(base))  # 基准归位
    # 
    #         if base_index == K:   # 判断目前已归位的基准,是不是第K位
    #             return nums[base_index]
    #         elif base_index > K:  # 递归左半部分
    #             return self.select(nums, left, base_index - 1, K)
    #         else:                 # 递归右半部分
    #             return self.select(nums, base_index + 1, right, K)
    # 
    #     def MoreThanHalfNum_Solution(self, numbers):
    #         if not numbers:
    #             return 0
    # 
    #         left, right = 0, len(numbers) - 1
    #         length = len(numbers)
    #         K = right // 2
    #         ans = self.select(numbers, left, right, right - K + 1)  # 第K大,就是第N-K+1小
    # 
    #         # 核实
    #         cnt = 0
    #         for x in numbers:
    #             if x == ans:
    #                 cnt += 1
    #                 if cnt == length // 2 + 1:
    #                     return ans
    #         return 0
    
    
    # class Solution:
    #     # 方法2
    #     def MoreThanHalfNum_Solution(self, numbers):
    #         if not numbers:
    #             return []
    #         if len(numbers) == 1:
    #             return numbers[0]
    #
    #         d = {}
    #         length = len(numbers)
    #
    #         for x in numbers:
    #             if x not in d:
    #                 d[x] = 1
    #             else:
    #                 d[x] += 1
    #                 if d[x] == length//2+1:
    #                     return x
    #         return 0
    
    
    class Solution:  
        # 方法3
        def MoreThanHalfNum_Solution(self, numbers):
            result = numbers[0]
            times = 1
    
            for x in numbers:
                if x == result:
                    times += 1
                elif times == 0:
                    result = x
                    times = 1
                else:
                    times -= 1
            # 核实
            length = len(numbers)
            cnt = 0
            for x in numbers:
                if x == result:
                    cnt += 1
                    if cnt == length // 2 + 1:
                        return result
            return 0
    
    
    s = Solution()
    ans = s.MoreThanHalfNum_Solution([1, 2, 3, 2, 2, 2, 5, 4, 2])
    print(ans)
    

    有序数组中出现次数超过25%的元素和方法三类似。

  • 相关阅读:
    yocto/bitbake 学习资源
    QEMU/KVM学习资源
    ubuntu 中创建和删除用户
    git 重命名本地和远程分支
    Ubuntu 上搭建 FTP 服务器
    gdb 常见用法
    git log 显示与特定文件相关的 commit 信息
    基于 qemu system mode 运行 arm 程序
    基于 qemu user mode 运行 aarch64 程序
    checking in(airport)
  • 原文地址:https://www.cnblogs.com/ldy-miss/p/12120909.html
Copyright © 2020-2023  润新知