PAT-A 1048. Find Coins (25)

来源:互联网 发布:苹果打开数据的快捷键 编辑:程序博客网 时间:2024/06/18 14:29

题目链接在此。

该题解题记录目前有:散列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 法

思路

  1. 先用sort排序
  2. 用两个指针i,j分别指向排序之后的数组的首尾端
    a[i]+a[j] == pay,输出结果,退出循环
    a[i]+a[j] > pay,j–
    a[i]+a[j] < pay,i++
  3. 判断是否已经输出了结果,没有输出则表示没知道到合适的解,输出”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;}
0 0
原创粉丝点击