我的PAT-ADVANCED代码仓:https://github.com/617076674/PAT-ADVANCED
原题链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805432256675840
题目描述:
题目翻译:
1048 寻找硬币
伊娃喜欢收集来自宇宙各处的硬币,包括其他一些像火星一样的行星。 有一天,她参观了一个可以接受各种硬币作为付款的通用购物中心。 但是,付款有一个特殊要求:对于每个账单,她只能使用两个硬币来支付确切的金额。 但是她有多达10 ^ 5个硬币,她需要你的帮助。 对于任何给定数额的钱,你应该告诉她,她是否可以找到两个硬币来支付它。
输入格式:
每个输入文件包含一个测试用例。对每个测试用例,第一行包含两个正整数:N(<= 10 ^ 5,代表硬币总数),M(<= 10 ^ 3,代表伊娃需要支付的总金额)。第二行包含了N个不超过500的正数,分别代表N个硬币的面值。一行中的所有数字都由一个空格分隔。
输出格式:
对每个测试用例,在第一行打印选取的两个硬币面值V1和V2,使其满足条件V1 + V2 = M且V1 < V2。如果这样的解决方案不唯一,输出V1最小的解决方案。如果找不到解决方案,输出No Solution。
输入样例1:
8 15
1 2 8 7 2 4 11 15
输出样例1:
4 11
输入样例2:
7 14
1 8 7 2 4 11 15
输出样例2:
No Solution
知识点:双指针、二分查找法
思路一:先对N枚硬币按面值从小到大排序,再用左右双指针遍历即可
由于题目只要找V1最小的一个解决方案,一旦找到解决方案就break出循环。
时间复杂度是O(NlogN)。空间复杂度是O(1)。
C++代码:
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int N, M;
scanf("%d%d", &N, &M);
int nums[N];
for(int i = 0; i < N; i++){
scanf("%d", &nums[i]);
}
sort(nums, nums + N);
int left = 0;
int right = N - 1;
while(left < right){
if(nums[left] + nums[right] == M){
printf("%d %d\n", nums[left], nums[right]);
break;
}else if(nums[left] + nums[right] < M){
left++;
}else{
right--;
}
}
if(left >= right){
printf("No Solution\n");
}
return 0;
}
C++解题报告:
思路二:先对N枚硬币按面值从小到大排序,再用二分查找法
对于每一个索引i,寻找在[i + 1, N)范围内寻找另一个索引j,使得nums[i] + nums[j] == M。一旦找到就break出循环。
时间复杂度是O(NlogN)。空间复杂度是O(N)。
C++代码:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main(){
int N, M;
scanf("%d %d", &N, &M);
int nums[N];
for(int i = 0; i < N; i++){
scanf("%d", &nums[i]);
}
sort(nums, nums + N);
vector<int> result;
for(int i = 0; i < N; i++){
int find = M - nums[i];
int j = lower_bound(nums + i + 1, nums + N, find) - nums;
if(j == N){
continue;
}
if(nums[j] + nums[i] == M){
result.push_back(nums[i]);
result.push_back(nums[j]);
break;
}
}
if(result.size() == 0){
printf("No Solution\n");
}else{
printf("%d %d", result[0], result[1]);
}
return 0;
}
C++解题报告: