TT的神秘礼物

本文介绍了一个有趣的算法挑战,通过二分查找和排序技巧,求解由猫咪数组生成的新数组的中位数。这是一个考验编程技能和数学思维的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:

TT 是一位重度爱猫人士,每日沉溺于 B 站上的猫咪频道。

有一天,TT 的好友 ZJM 决定交给 TT 一个难题,如果 TT 能够解决这个难题,ZJM 就会买一只可爱猫咪送给 TT。

任务内容是,给定一个 N 个数的数组 cat[i],并用这个数组生成一个新数组 ans[i]。新数组定义为对于任意的 i, j 且 i != j,均有 ans[] = abs(cat[i] - cat[j]),1 <= i < j <= N。试求出这个新数组的中位数,中位数即为排序之后 (len+1)/2 位置对应的数字,'/' 为下取整。

TT 非常想得到那只可爱的猫咪,你能帮帮他吗?o

input:

多组输入,每次输入一个 N,表示有 N 个数,之后输入一个长度为 N 的序列 cat, cat[i] <= 1e9 , 3 <= n <= 1e5

output:

输出新数组 ans 的中位数

sample input:

4
1 3 2 4
3
1 10 2

sample output:

1
8

题解:

  1. 对于我们这个题来说,我们的目的是求cat[i]-cat[j]的中位数,我们首先来想,怎样求中位数。我们求中位数就是按照名次来,而对于这个我们是不是可以用二分法来比较一个数的名次是不是等于我们这个中位数的名次。

  2. 根据上面的分析,我们来看,二分时,一个数的名次如果大于中位数的名次,那么就去比他小的一半来,反之亦然。

  3. 那么我们如何来计算每一个结果的名次呢,因为名次意味这有多少个结果比自己小,那么我们就可以先对cat进行排序,就可以将绝对值去除,去除之后,我们就去寻找有多少结果比该结果小。对于每一个i,我们去判断j的个数,使catj-cati小于该结果,就是这个结果的名次。

  4. 因此,我们可以使用两个二分对于我们的这个实验进行解决。

完整代码:

#include <iostream>
#include<stdio.h>
#include<stdlib.h>
#include <algorithm> 
#include <cstring>
#include <cmath>
using namespace std; 
int cat[100010];
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int find(int *cat,int size,int a)       //找到一个数在有序数列中的位次 
{
	int l=0;
	int r=size-1;
	int count=-1;
	int mid;
	while(l<=r)
	{
		mid=(l+r)>>1;
		if(cat[mid]<=a)
		{
			count=mid;
			l=mid+1;
		}
		else if(cat[mid]>a)
		{
			r=mid-1;
		}
	}
	return count;
}
int main(int argc, char** argv) {
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		for(int i=0;i<n;i++)
		{
			scanf("%d",cat+i);

		}
		sort(cat,cat+n);
		int realmid=((n*(n-1)/2)+1)/2;
		
		int mid=0;
		int l=0;
		int r=cat[n-1]-cat[0];
		int ans;
		//...................//二分找中位数
		
		while(l<=r)
		{
			int rank=0;
			mid=(l+r)>>1;
			for(int i=0;i<n;i++)
			{
				int a=find(cat,n,cat[i]+mid);
				if(a!=-1)
				{
					rank+=(a-i);
				}
			}
			
			if(rank>=realmid)
			{
				ans=mid;
				r=mid-1;
			}
			else
			{
				l=mid+1;
			}
		 } 
		cout<<ans<<endl;
		
	}
	

	return 0;
}

反思:

对于这个实验,其实就是我们对于二分发的应用,但是在解题思路上是不容易想到的,所以我们要多刷题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值