PAT-A 1048. Find Coins (25)

题目链接在此

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值