1 条题解

  • 1
    @ 2025-4-8 21:29:18

    题意分析

    题目背景设定在一个特殊情境中,修士们面临着院长要求机器找出和为1000010000的两个数的任务,而机器仅能判断两数之和与1000010000的大小关系。现在有两个修士各自准备了一个整数列表,需要判断是否能从这两个列表中挑选出两个数,使它们的和恰好等于1000010000

    输入条件:输入包含两个列表,每个列表的第一行是该列表数字的数量NiN_i,取值范围是1Ni500001\leq N_i\leq50000 。接着是NiN_i行,每行一个整数,这些整数的范围在32768-327683276732767之间。并且第一个列表是递增顺序排列,第二个列表是递减顺序排列。

    输出要求:如果能从两个列表中选出和为1000010000的两个数,程序要向标准输出写入“YES”;反之,如果不存在这样的两个数,则输出“NO”。

    解题思路

    由于两个列表分别是递增和递减的,这一特性为高效解题提供了关键线索,因此可以采用双指针法来解决该问题。

    1. 初始化指针:设置两个指针,一个指针(设为ii)指向第一个递增列表的起始位置,另一个指针(设为jj)指向第二个递减列表的起始位置。这两个指针用于遍历两个列表中的元素。

    2. 计算和并比较:计算两个指针所指向元素的和sumsum,即sum=第一个列表[i]+第二个列表[j]sum = 第一个列表[i] + 第二个列表[j]。然后将sumsum与目标值1000010000进行比较。

    情况一:和等于10000:若sumsum恰好等于1000010000,这就表明找到了满足条件的两个数,此时直接得出结论,程序输出“YES”并结束。

    情况二:和小于10000:当sumsum小于1000010000时,因为第一个列表是递增的,为了使和增大,更接近目标值1000010000,将指向第一个列表的指针ii向后移动一位,即i=i+1i = i + 1 。这样就可以获取第一个列表中的下一个较大的数,再重新计算和并进行比较。

    情况三:和大于10000:要是sumsum大于1000010000,鉴于第二个列表是递减的,为了让和减小,将指向第二个列表的指针jj向后移动一位,即j=j+1j = j + 1 。如此便会获取第二个列表中的下一个较小的数,接着重新计算和并判断。

    3. 循环与结果判断:不断重复上述计算和比较的步骤,持续这个过程,直到其中一个指针超出了它所在列表的范围。如果在遍历过程中找到了和为1000010000的两个数,程序已经输出“YES”并结束;若遍历结束后仍未找到,那就说明不存在满足条件的两个数,此时程序输出“NO”。

    这种双指针法充分利用了列表的有序性,避免了对所有可能组合的暴力枚举,大大提高了算法的效率,将时间复杂度控制在O(N1+N2)O(N_1 + N_2),其中N1N_1N2N_2分别是两个列表的长度。

    代码实现

    #include<stdio.h>
    #include<stdlib.h>
    const int maxN=50000 + 50;
    int a[maxN],b[maxN];
    
    int main()
    {
    	int n,m;
    	while(scanf("%d",&n)==1){
    		int i;
    		for(i=0;i<n;++i)
    			scanf("%d",&a[i]);
    		scanf("%d",&m);
    		for(i=0;i<m;++i)
    			scanf("%d",&b[i]);
    		int p=0,q=0;
    		int ans=0;
    		while(p<n&&q<m){
    			if(a[p]+b[q]==10000){
    				ans=1;
    				break;
    			}
    			else if(a[p]+b[q]<10000)
    				++p;
    			else
    				++q;
    		}
    		printf("%s\n",ans==0?"NO":"YES");
    	}
    	return 0;
    }
    
    

    代码说明:

    1.头文件包含:#include <stdio.h>和#include <stdlib.h>分别引入了标准输入输出库和标准库,使得代码可以使用scanf、printf等函数进行输入输出操作,以及使用stdlib.h中的一些标准函数(虽然在此代码中未用到,但引入是一种常见的编程习惯)。

    2.常量和数组定义:const int maxN = 50000 + 50;定义了一个常量maxN,表示数组的最大长度,额外加 50 是为了预留一定的空间,防止数组越界(尽管在本题中不一定需要,但在一些复杂情况下可提供一定的安全性)。int a[maxN], b[maxN];定义了两个整型数组a和b,用于存储输入的两个整数列表。

    3.主函数和输入读取:int main()是程序的入口函数。在主函数中,首先定义了变量n和m,用于存储两个数组的长度。然后通过while (scanf("%d", &n) == 1)循环读取输入数据,只要成功读取到一个整数n(表示第一个数组的长度),就进入循环体。在循环体中,使用for循环读取n个整数存入数组a中,接着读取第二个数组的长度m,再使用for循环读取m个整数存入数组b中。

    4.双指针查找和结果判断:定义指针p和q,初始值为 0,分别指向数组a和b的起始位置;定义变量ans,初始值为 0,用于标记是否找到满足条件的数对。通过while (p < n && q < m)循环进行双指针查找,在循环体中,根据a[p] + b[q]与 10000 的比较结果移动指针p或q。如果找到和为 10000 的数对,将ans设为 1 并使用break跳出循环。

    5.输出结果:最后,使用printf("%s\n", ans == 0? "NO" : "YES");根据ans的值输出相应的结果。如果ans为 0,输出 “NO”;如果ans为 1,输出 “YES”。整个程序通过双指针法高效地解决了从两个有序数组中查找和为 10000 的数对的问题。

    • 1