PAT——A1025 Median(two pointers)

题目链接

内存超限(最后一个测试点过不去???内存这么小的吗)

#include<bits/stdc++.h>
using namespace std;
int a[1000010];
int b[1000010];
int c[1000010];
void merge(int a[],int b[],int c[],int m,int n)
{
    int i=0,j=0,index=0;
    while(i<m&&j<n)
    {
        if(a[i]<=b[j])
        {
            c[index++]=a[i++];
        }
        else
        {
            c[index++]=b[j++];
        }
    }
    while(i<m)
        c[index++]=a[i++];
    while(j<n)
        c[index++]=b[j++];
   // return index;
}
int main()
{
    int m,n;
    scanf("%d",&m);
    for(int i=0;i<m;i++)
    {
        scanf("%d",&a[i]);
    }
    sort(a,a+m);
     scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&b[i]);
    }
    sort(b,b+n);
    merge(a,b,c,m,n);
    printf("%d\n",c[(m+n-1)/2]);
    return 0;
}

看了大神的博客

然后知道了

归并排序超内存了

大神用了队列的方法

维护两个队列,比较对头大小,循环出列

第一个队列存好后

把第二个队列边读

边和第一个队列比较,选择出队

这样就不用一次存完第二个队列

解决超内存的问题

第一、二个序列分别有n、m个元素

所以需要从队头剔除(n+m-1)/2个元素

最后答案就是两个队头的最小值

而最终答案在第一第二个队列中的情况要分开处理

若答案在第二个队列中

在输入数据时就可以提前得出答案并退出

若答案在第一个队列中,要二次出队才能找到答案

注意点:

在所有元素入队列完毕后,把INT_MAX入队列

一是这样队列永不为空,方便处理

二是,题目中的long int因为内存限制的原因,并不会为最终答案,只是干扰数据

所以每次遇到这样的干扰数据把他设为INT_MAX即可

#include<bits/stdc++.h>
using namespace std;
int main()
{
    queue<int>a,b;
    long long tnum;
    int n,m,num,cnt=0;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%lld",&tnum);
        num=min((long long)INT_MAX,tnum);
        a.push(num);
    }
    a.push(INT_MAX);
    scanf("%d",&m);
    for(int i=0;i<m;i++)
    {
        scanf("%lld",&tnum);
        num=min((long long)INT_MAX,tnum);
        b.push(num);
        if(cnt==(n+m-1)/2)
        {
            printf("%d",min(a.front(),b.front()));
            return 0;
        }
        if(a.front()<b.front())
        {
            a.pop();
        }
        else
            b.pop();
        cnt++;
    }
    b.push(INT_MAX);
    for(;cnt<(n+m-1)/2;cnt++)
    {
        if(a.front()<b.front())
            a.pop();
        else
            b.pop();
    }
    printf("%d",min(a.front(),b.front()));
    return 0;
}

再次感叹下

这个大大为啥这么强

但是有一个不理解的点

为什么第一个队列要分出来才能输出

【懂了!!!】

就是如果第一个队列的长度大于第二个

那其实还没有到中位数就直接循环结束了

所以还应有下一个循环进行遍历

参考博客

双针法:(第二个数组边读边读入)

#include <cstdio>
#include <cstdlib>

const int INF = 0x7fffffff;
int main() {
    int l1, l2, i, j, count = 0;
    int *a1, a2;

    scanf("%d", &l1);
    a1 = (int *)malloc((l1 + 1) * sizeof(int));
    for (i = 0; i < l1; i++)
        scanf("%d", a1 + i);
    *(a1 + l1) = INF;
    scanf("%d", &l2);
    //a2 = (int *)malloc((l2 + 1) * sizeof(int));
    //for (i = 0; i < l2; i++)
    //  scanf("%d", a2 + i);
    //*(a2 + l2) = INF;

    int mid = (l1 + l2 - 1) / 2;            // l1 = mediapos
    i = j = 0;
    scanf("%d", &a2);
    while (count < mid)
    {
        if (*(a1 + i) < a2) i++;
        else {
            j++;
            if (j < l2)
            {
                scanf("%d", &a2);
            }
            else if (j == l2)
                a2 = INF;
            else
                break;
        }
        count++;
    }

    printf("%d\n", *(a1 + i) < a2 ? *(a1 + i) : a2);

    return 0;
}

参考博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值