pat甲级-1044-Shopping in Mars (25)

欢迎访问我的pat甲级题解目录哦https://blog.csdn.net/richenyunqi/article/details/84981078

题目描述

pat甲级-1044-Shopping in Mars (25)_第1张图片

题意分析

给定一组数字,判断这组数字中能否找出连续的一串数字,使得找到的这些数字之和为M。如果能找到输出所有可能的连续数字的首尾位置;如果找不到,输出所有可能的能够使得加和最小且要大于M的一串数字的首尾位置。题目保证给定的一组数字之和大于等于M

算法设计

两种方法:two pointers和二分查找。

two pointers

将输入的一组数字存储在数组A中,定义两个索引 i 表示当前一串数字的左界,j 表示当前一串数字的右界,初始化均为0 ,保证其指向数组的第一个元素,定义变量sum=0,表示当前这一串数字之和,每当sumM,令sum-=A[i],同时 i 右移一个元素。当 j 超过数组维度的时候,算法终止。

上述算法可以找到所有使得数字总和等于M的一串数字的首尾位置。为了找到所有可能的能够使得加和最小且要大于M的一串数字的首尾位置,可以对上述算法做出一些修改,定义一个vector>存储将当前这一串数字的首尾位置加入vector中,定义一个变量maxSum表示当前vector中存储的大于M的一串数字的和。在上述算法执行过程中,如果遇到总和大于M且总和小于maxSum的一串数字,即清空vector,同时更新maxSum,并将当前这一串数字的首尾位置加入vector中;如果遇到总和大于M且总和等于maxSum的一串数字,直接将当前这一串数字的首尾位置加入vector中。当算法执行完毕,vector中存储的即为所有可能的能够使得加和最小且要大于M的一串数字的首尾位置。

C++代码

#include 
using namespace std;
int main(){
    int N,M,sum=0,maxSum=INT_MAX;
    scanf("%d%d",&N,&M);
    int A[N];
    vector>v;//存储加和最小且要大于M的一串数字的首尾位置
    for(int i=0;iM&&sumM&&sum==maxSum
                v.push_back({i+1,j});//将当前这一串数字的首尾位置加入vector中
            sum-=A[i++];//sum-=A[i],i右移一个元素
        }
    if(maxSum!=-1)//maxSum不为-1,表示没有找到总和等于M的一组数字,输出vector中的数字
        for(int i=0;i

二分查找

令A[i]表示给定的一组数中第1个数到第i个数的和,为了后续计算方便,可令A[0]=0 。很明显,A数组必然是一个递增的数组,那么可以利用二分查找的方法。枚举左端点i,然后在A数组的[i+1,N]范围内利用二分查找算法找到第一个使得A[j]-A[i]>=M的右端点 j。如果A[j]-A[i]==M,说明由i 到j 这段数组符合要求,输出此时的左端点i 和右端点 j 即可。

上述算法可以找到所有使得数字总和等于M的一串数字的首尾位置。为了找到所有可能的能够使得加和最小且要大于M的一串数字的首尾位置,可以对上述算法做出一些修改,定义一个vector>存储将当前这一串数字的首尾位置加入vector中,定义一个变量maxSum表示当前vector中存储的大于M的一串数字的和。在上述算法执行过程中,如果遇到总和大于M且总和小于maxSum的一串数字,即清空vector,同时更新maxSum,并将当前这一串数字的首尾位置加入vector中;如果遇到总和大于M且总和等于maxSum的一串数字,直接将当前这一串数字的首尾位置加入vector中。当算法执行完毕,vector中存储的即为所有可能的能够使得加和最小且要大于M的一串数字的首尾位置。

自定义二分查找函数的c++代码

#include 
using namespace std;
int N,M,maxSum=INT_MAX;
int f(int A[],int left,int right,int value){//自定义的返回在[left,right]区间内第一个大于等于value的位置的函数
    int mid;
    while(left=value)
            right=mid;
        else
            left=mid+1;
    }
    return left;
}
int main(){
    scanf("%d%d",&N,&M);
    int A[N+1]={0};//表示给定的一组数中第1个数到第i个数的和,A[0]=0
    vector>v;//存储加和最小且要大于M的一串数字的首尾位置
    for(int i=1;iM&&A[j]-A[i]M&&A[j]-A[i]M&&A[j]-A[i]==maxSum)//如果A[j]-A[i]>M&&A[j]-A[i]==maxSum
            v.push_back({i+1,j});//将当前这一串数字的首尾位置加入vector中
    }
    if(maxSum!=-1)//maxSum不为-1,表示没有找到总和等于M的一组数字,输出vector中的数字
        for(int i=0;i

使用标准库自带的二分查找函数的c++代码

#include 
using namespace std;
int N,M,maxSum=INT_MAX;
int main(){
    scanf("%d%d",&N,&M);
    int A[N+1]={0};//表示给定的一组数中第1个数到第i个数的和,A[0]=0
    vector>v;//存储加和最小且要大于M的一串数字的首尾位置
    for(int i=1;iM&&A[j]-A[i]M&&A[j]-A[i]M&&A[j]-A[i]==maxSum)//如果A[j]-A[i]>M&&A[j]-A[i]==maxSum
            v.push_back({i+1,j});//将当前这一串数字的首尾位置加入vector中
    }
    if(maxSum!=-1)//maxSum不为-1,表示没有找到总和等于M的一组数字,输出vector中的数字
        for(int i=0;i

 

你可能感兴趣的:(pat甲级)