中位数问题

题意:
给定一个 N 个数的数组 cat[i],并用这个数组生成一个新数组 ans[i]。新数组定义为对于任意的 i, j 且 i != j,均有 ans[] = abs(cat[i] - cat[j]),1 <= i < j <= N。试求出这个新数组的中位数,中位数即为排序之后 (len+1)/2 位置对应的数字,’/’ 为下取整。
输入:
多组输入,每次输入一个 N,表示有 N 个数,之后输入一个长度为 N 的序列 cat, cat[i] <= 1e9 , 3 <= n <= 1e5
输出:
输出新数组 ans 的中位数
输入样例:
4
1 3 2 4
3
1 10 2
输出样例:
1
8
解题思路:
10^5 的数据量,n^2 的复杂度计算出新的数组不可取。我们选择不计算新的数组具体是怎么样的,转而利用二分的思想求出某一个数然后判断是不是中位数,不停地二分逼近最终得到具体的中位数是多少。新数列的最小值不会小于0,对原数列按从小到大排序有利于去掉绝对值符号,新数组的最大值为cat的最后一个减去cat的第一个。判断一个数x在新数组中的位置的方法是计算所有小于等于x的数的个数,即xj-xi<=x(j>i)这样的数对的个数,即xj<=xi+x(j>i),我们对i进行循环枚举,得到xi+x的值,然后判断在原数列中最后一个小于等于xi+x的xj的位置,然后这样的数对的个数需要增加的值是这个xj的位置减去当前枚举的xi的下标i。我们用刚刚提到的0和cat的最后一个减去cat的第一个的最大值来开始二分,得到每一个mid值的位置pos,pos>=中位数应该的position((n*(n-1)+2)/4)时,把mid-1赋给r,否则mid+1赋给l,这样可以找到pos>=中位数应该的position((n*(n-1)+2)/4)的最小的数,这个数就一定是我们要找的中位数。
注意事项:
1、用cin读入比scanf更快。
2、不能在(pos=pos_of_mid)时就停止二分,要在l>r时停止二分,因为即使pos==pos_of_mid时得到的数可能仍比中位数大,我们需要找到pos>=中位数应该的position((n*(n-1)+2)/4)的最小的数才行。
总结:
一道较有难度的二分思想的题目,需要用到多次二分,求一个数在新数列中的位置时使用二分,整个题目的求解思路也是以二分为基础来寻找中位数的,这种不求出具体数组但通过二分寻求中位数的思想比较重要。求一个数在新数列中的位置时所使用的单次枚举的思路也能有效优化降低时间复杂性。
参考代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <iomanip>
#include <map>
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是中位数问题的分治法伪代码: ``` def find_median(nums): n = len(nums) if n % 2 == 1: # 如果数组元素个数是奇数 return quick_select(nums, n // 2) # 直接找到第 n//2 小的元素即为中位数 else: # 如果数组元素个数是偶数 return (quick_select(nums, n // 2 - 1) + quick_select(nums, n // 2)) / 2 # 找到第 n//2 - 1 小和第 n//2 小的元素,取平均值作为中位数 def quick_select(nums, k): if len(nums) == 1: # 如果只有一个元素,则返回该元素 return nums[0] pivot = random.choice(nums) # 随机选择一个枢轴元素 left = [x for x in nums if x < pivot] # 将小于枢轴的元素放到左边数组 right = [x for x in nums if x > pivot] # 将大于枢轴的元素放到右边数组 mid = [x for x in nums if x == pivot] # 将等于枢轴的元素放到中间数组 if k < len(left): # 如果第 k 小的元素在左边数组中,递归处理左边数组 return quick_select(left, k) elif k < len(left) + len(mid): # 如果第 k 小的元素在中间数组中,直接返回中间数组的第一个元素 return mid[0] else: # 如果第 k 小的元素在右边数组中,递归处理右边数组 return quick_select(right, k - len(left) - len(mid)) ``` 其中,`quick_select` 函数用于找到第 k 小的元素,`find_median` 函数用于找到数组的中位数。在 `find_median` 函数中,如果数组元素个数是奇数,则直接找到第 n//2 小的元素即为中位数;如果数组元素个数是偶数,则找到第 n//2 - 1 小和第 n//2 小的元素,取平均值作为中位数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值