欢迎访问我的pat甲级题解目录哦https://blog.csdn.net/richenyunqi/article/details/84981078
给定一组数字,判断这组数字中能否找出连续的一串数字,使得找到的这些数字之和为M。如果能找到输出所有可能的连续数字的首尾位置;如果找不到,输出所有可能的能够使得加和最小且要大于M的一串数字的首尾位置。题目保证给定的一组数字之和大于等于M
两种方法:two pointers和二分查找。
将输入的一组数字存储在数组A中,定义两个索引 i 表示当前一串数字的左界,j 表示当前一串数字的右界,初始化均为0 ,保证其指向数组的第一个元素,定义变量sum=0,表示当前这一串数字之和,每当sum
上述算法可以找到所有使得数字总和等于M的一串数字的首尾位置。为了找到所有可能的能够使得加和最小且要大于M的一串数字的首尾位置,可以对上述算法做出一些修改,定义一个vector
#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
#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
#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