zoukankan      html  css  js  c++  java
  • 【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%的元素和方法三类似。

  • 相关阅读:
    当接口请求体里的日期格式跟web页面日期格式不一致时,该如何处理呢?
    巧妙利用selenium中的JS操作来处理特殊的文本框
    web自动化针对PO模式进行二次封装之basepage
    基于python的selenium两种文件上传操作
    selenium三大切换的骚操作之显性等待
    基于python的selenium常用操作方法(2)
    基于python的selenium常用操作方法(1)
    selenium常用的三种等待方式
    使用suds模块进行封装,处理webservice类型的接口
    使用csv模块读写csv格式文件
  • 原文地址:https://www.cnblogs.com/ldy-miss/p/12120909.html
Copyright © 2011-2022 走看看