P1631 序列合并

题目出处

题目描述

       有两个长度都是 N 的序列 A 和 B ,在 A 和 B 中各取一个数相加可以得到 N2 个和,求这 N2 个和中最小的 N 个。

输入格式

       第一行一个正整数 N 。
       第二行 N 个整数 Ai ,满足 Ai≤Ai+1 且Ai≤109
​       第三行 N 个整数 Bi ,满足 Bi≤Bi+1 且Bi≤109

数据规模

       对于50%的数据中,满足 1≤N≤1000 。
       对于100%的数据中,满足1≤N≤100000

输出格式

       输出仅一行,包含 N 个整数,从小到大输出这 N 个最小的和,相邻数字之间用空格隔开。

输入输出样例

输入样例

3
2 6 6
1 4 8

输出样例

3 6 7

AC代码与思路

       两个数组输入的数是有序的。

数学方法

       若数组 A 和数组 B 有序,且 A[ i ]+B[ j ] 是 A[ k ]+B[ m ] 中前N小的值,那么必然有:A[ i ]*B[ j ] ≤ N。其中 1≤ i ≤N,1≤ j ≤N,1≤ k ≤N,1≤ m ≤N。

#include <stdio.h>
#include <algorithm>

using namespace std;

int main()
{
    int i, j, k = 0;
    int n;
    int NumSet1[100000] = {0};
    int NumSet2[100000] = {0};
    static int Sum[1300000] = {0};

    scanf("%d", &n);
    for (i = 0; i < n; i++)
        scanf("%d", &NumSet1[i]);
    for (i = 0; i < n; i++)
        scanf("%d", &NumSet2[i]);

    for (i = 0; i < n; i++)
        for (j = 0; (i + 1) * (j + 1) <= n; j++)
            Sum[k++] = NumSet1[i] + NumSet2[j];

    partial_sort(Sum, Sum + k, Sum + k);

    for (i = 0; i < n; i++)
        printf("%d ", Sum[i]);
    printf("\n");
}

优先队列

#include <iostream>
#include <queue>
#include <algorithm>

using namespace std;

#define MaxSize 100010

typedef struct SumWithFactor
{
    int FactorANo;
    int FactorBNo;
    int Sum;

    //优先队列默认大顶堆,改变"<"定义,使其变成小顶堆
    bool friend operator<(SumWithFactor Sum1, SumWithFactor Sum2)
    {
        return Sum1.Sum > Sum2.Sum;
    }
} SumWithFactor;

int main()
{
    int n;
    int NoA, NoB;
    int NumSetA[MaxSize] = {0}, NumSetB[MaxSize] = {0};

    SumWithFactor Temp;
    priority_queue<SumWithFactor> SumList;

    //关闭流同步
    ios::sync_with_stdio(false);
    cin >> n;

    for (int i = 0; i < n; ++i)
        cin >> NumSetA[i];

    for (int i = 0; i < n; ++i)
        cin >> NumSetB[i];

    //生成一个长度为n的优先队列
    //该队列由A[i]+B[0]组成(i=0,1,2……,n-1)
    for (int i = 0; i < n; ++i)
    {
        Temp.FactorANo = i;
        Temp.FactorBNo = 0;
        Temp.Sum = NumSetA[i] + NumSetB[0];
        SumList.push(Temp);
    }

    //若A[i]+B[j]被取出队列,将A[i]+B[j+1]放入队列
    //按此取出n个元素,该n个元素即为最小的n个元素
    for (int i = 0; i < n; ++i)
    {
        Temp = SumList.top();
        cout << Temp.Sum << " ";    //注意输出格式
        SumList.pop();
        ++Temp.FactorBNo;
        Temp.Sum = NumSetA[Temp.FactorANo] + NumSetB[Temp.FactorBNo];
        SumList.push(Temp);
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述: 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例: 输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4 解题思路: 这道题可以使用递归和迭代两种方法来解决。 递归方法: 首先,如果两个链表中有一个是空链表,那么直接返回另一个链表即可。如果两个链表都不为空,则比较两个链表的头节点,将较小的那个节点作为合并后链表的头节点,并递归地将较小节点的 next 与另一个链表的头节点继续合并。最后返回合并后的链表头节点即可。 迭代方法: 首先,需要定义一个哑节点 dummy,用来表示合并后的链表的头节点。然后,定义一个指针 p,初始时指向 dummy 节点。接着,比较两个链表的头节点,将较小的那个节点插入到 p 的后面,并将 p 向后移动一位。最后,将较小节点所在的链表的头节点向后移动一位,并继续进行比较和插入操作,直到一个链表为空。最后,将另一个链表的剩余节点插入到合并后的链表的尾部,返回 dummy.next 即可。 代码实现: 递归方法: class Solution { public: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { if (!l1) return l2; if (!l2) return l1; if (l1->val < l2->val) { l1->next = mergeTwoLists(l1->next, l2); return l1; } else { l2->next = mergeTwoLists(l1, l2->next); return l2; } } }; 迭代方法: class Solution { public: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { ListNode* dummy = new ListNode(-1); ListNode* p = dummy; while (l1 && l2) { if (l1->val < l2->val) { p->next = l1; l1 = l1->next; } else { p->next = l2; l2 = l2->next; } p = p->next; } if (l1) p->next = l1; if (l2) p->next = l2; return dummy->next; } };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值