题目链接在此。
该题解题记录目前有:散列hashTable方法、二分查找方法、Two pointers法。
题意
给定两个整数N,M,给出N个硬币的面值(面值<=500),问是否存在两枚硬币v1,v2,是的v1+v2==M,并且v1<=v2。如果答案不唯一,输出a最小的那一对。
散列hashTable方法
思路
定义一个hashTable数组用来记录每种面值硬币的个数
v1从1开始枚举到m/2+1(因为再往后就没有必要了,那样只是v1和v2的值对调了一下),hashTable[v1]–(主要为v1==v2的情况服务),如果hashTable[M-v1] >0则说明存在,否则查询v1的下一个。
AC代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int main(){
int N,pay;
scanf("%d %d",&N, &pay);
int hashTable[1001] = {0}; //注意hashTable的大小
int temp;
for(int i = 0; i < N; i++){
scanf("%d",&temp);
hashTable[temp]++;
}
int v1;
for(v1 = 1; v1 < pay/2+1; v1++){
if(hashTable[v1] > 0){ //有v1面值的coin
hashTable[v1]--; //v1面值的-1
int v2 = pay - v1;
if(hashTable[v2] > 0){ //有和v1对应的v2的面值的coin,则可以凑成
printf("%d %d\n",v1,v2);
break;
}
}
}
if(v1 >= pay/2+1){ //没找到符合题意的
printf("No Solution\n");
}
return 0;
}
二分查找法
思路
用数组a[]保存输入,之后i从0~n-1枚举每个数,然后对0~n-1这个区间内的元素做二分查找,找到一个即可输出然后退出循环。
注意:二分查找需要序列有序。
AC代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[100010];
//二分查找数组a[]的left到right区间内a[mid] == x
int binary_search(int left, int right, int x){
while(left <= right){
int mid = (left+right)/2;
if(a[mid] == x){
return mid;
}else if(a[mid] > x){
right = mid - 1;
}else { //a[mid] < x
left = mid + 1;
}
}
return -1;
}
int main(){
int n,pay;
scanf("%d %d",&n,&pay);
bool flag = false;
int v1 = 1000 , v2;
for(int i = 0; i < n; i++){
scanf("%d",a+i);
}
sort(a,a+n); //二分查找的前提是有序
int i;
for(i = 0; i < n; i++){
int ans = binary_search(0,n-1,pay-a[i]); //查找i~n-1的序列中,a[i]等于pay-a[1](即v2)的值
if(ans != -1 && ans != i){ //注意:返回的结果是本元素的情况不是能要的
printf("%d %d\n",a[i],a[ans]);
break; //只需要输出v1最小的,由于已经从小到大排序,所以输出一个即可退出
}
}
if(i == n){ //没有找到符合要求的元素
printf("No Solution\n");
}
return 0;
}
two pointers 法
思路
- 先用sort排序
- 用两个指针i,j分别指向排序之后的数组的首尾端
a[i]+a[j] == pay,输出结果,退出循环
a[i]+a[j] > pay,j–
a[i]+a[j] < pay,i++ - 判断是否已经输出了结果,没有输出则表示没知道到合适的解,输出”No solution”
AC代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int main(){
int n,pay;
scanf("%d %d",&n,&pay);
int a[100010];
for(int i = 0; i < n; i++){
scanf("%d",&a[i]);
}
sort(a,a+n);
bool flag = false;
int i = 0,j = n-1;
while( i < n && j >= 0){
int sum = a[i]+a[j];
if(sum == pay && i!=j){ //注意i!=j
printf("%d %d",a[i],a[j]);
flag = true;
break;
}else if(sum < pay){
i++;
}else{
j--;
}
}
if(flag == false)
printf("No Solution\n");
return 0;
}
也可以写成这样:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int main(){
int n,pay;
scanf("%d %d",&n,&pay);
int a[100010];
for(int i = 0; i < n; i++){
scanf("%d",&a[i]);
}
sort(a,a+n);
int i = 0,j = n-1;
while( i < j){
int sum = a[i]+a[j];
if(sum == pay){ //注意i!=j
printf("%d %d",a[i],a[j]);
break;
}else if(sum < pay){
i++;
}else{
j--;
}
}
if(i == j){
printf("No Solution\n");
}
return 0;
}